Convert dib-request-list to image-status command

This augments the dib-request list (which shows what images have
manual build requests) with information about whether the image
is paused.  The resulting command is renamed to "image-status".

Change-Id: If75a8757b4ec93563e47bfdf0a239a9c21660c45
changes/92/847092/1
James E. Blair 3 months ago
parent d6e8bd72df
commit 138b68a5a7
  1. 10
      doc/source/operation.rst
  2. 14
      nodepool/cmd/nodepoolcmd.py
  3. 27
      nodepool/status.py
  4. 4
      nodepool/tests/unit/test_commands.py
  5. 22
      nodepool/tests/unit/test_webapp.py
  6. 4
      nodepool/webapp.py
  7. 7
      releasenotes/notes/image-status-bedca1dd0184c14b.yaml

@ -149,9 +149,9 @@ dib-image-list
.. program-output:: nodepool dib-image-list --help
:nostderr:
dib-request-list
^^^^^^^^^^^^^^^^
.. program-output:: nodepool dib-request-list --help
image-status
^^^^^^^^^^^^
.. program-output:: nodepool image-status --help
:nostderr:
image-list
@ -396,9 +396,9 @@ launchers, all will provide the same information.
:resheader Content-Type: ``application/json`` or ``text/plain``
depending on the :http:header:`Accept` header
.. http:get:: /dib-request-list
.. http:get:: /image-status
The status of manual build requests
The paused and manual build status of images
:query fields: comma-separated list of fields to display
:reqheader Accept: ``application/json`` or ``text/*``

@ -61,10 +61,10 @@ class NodePoolCmd(NodepoolApp):
help='list images built with diskimage-builder')
cmd_dib_image_list.set_defaults(func=self.dib_image_list)
cmd_dib_request_list = subparsers.add_parser(
'dib-request-list',
help='list image build requests')
cmd_dib_request_list.set_defaults(func=self.dib_request_list)
cmd_image_status = subparsers.add_parser(
'image-status',
help='list image status')
cmd_image_status.set_defaults(func=self.image_status)
cmd_image_build = subparsers.add_parser(
'image-build',
@ -208,8 +208,8 @@ class NodePoolCmd(NodepoolApp):
results = status.dib_image_list(self.zk)
print(status.output(results, 'pretty'))
def dib_request_list(self):
results = status.dib_request_list(self.zk)
def image_status(self):
results = status.image_status(self.zk)
print(status.output(results, 'pretty'))
def image_list(self):
@ -431,7 +431,7 @@ class NodePoolCmd(NodepoolApp):
# commands needing ZooKeeper
if self.args.command in ('image-build', 'dib-image-list',
'dib-request-list',
'image-status',
'image-list', 'dib-image-delete',
'image-delete', 'alien-image-list',
'list', 'delete',

@ -71,7 +71,7 @@ def _to_pretty_table(objs, headers_table, fields):
for k in headers_table:
if fields and k not in fields:
continue
if k == 'age':
if k == 'age' or k.endswith('_age') and obj[k] is not None:
try:
obj_age = age(int(obj[k]))
except ValueError:
@ -81,6 +81,8 @@ def _to_pretty_table(objs, headers_table, fields):
else:
if isinstance(obj[k], list):
values.append(','.join(obj[k]))
elif obj[k] is None:
values.append('')
else:
values.append(obj[k])
t.add_row(values)
@ -202,21 +204,28 @@ def dib_image_list(zk):
return (objs, headers_table)
def dib_request_list(zk):
def image_status(zk):
headers_table = OrderedDict([
("image", "Image"),
("state", "State"),
("age", "Age")
("paused", "Paused"),
("build_request", "Build Request"),
("build_request_age", "Build Request Age")
])
objs = []
for image_name in zk.getImageNames():
request = zk.getBuildRequest(image_name)
if request is None:
continue
paused = zk.getImagePaused(image_name)
if request:
age = int(request.state_time)
req = 'pending' if request.pending else 'building'
else:
age = None
req = None
objs.append({
"image": request.image_name,
"state": "pending" if request.pending else "building",
"age": int(request.state_time)
"image": image_name,
"paused": bool(paused),
"build_request": req,
"build_request_age": age,
})
return (objs, headers_table)

@ -193,7 +193,7 @@ class TestNodepoolCMD(tests.DBTestCase):
nodepoolcmd.main()
self.assert_listed(configfile, ['dib-image-list'], 4, zk.READY, 1)
def test_dib_request_list(self):
def test_image_status(self):
configfile = self.setup_config('node.yaml')
builder = self.useBuilder(configfile)
# Make sure we have enough time to test for the build request
@ -202,7 +202,7 @@ class TestNodepoolCMD(tests.DBTestCase):
worker._interval = 60
self.waitForImage('fake-provider', 'fake-image')
self.zk.submitBuildRequest("fake-image")
self.assert_listed(configfile, ['dib-request-list'],
self.assert_listed(configfile, ['image-status'],
0, 'fake-image', 1)
def test_dib_image_build_pause(self):

@ -138,7 +138,7 @@ class TestWebApp(tests.DBTestCase):
'formats': ['qcow2'],
'state': 'ready'}, objs[0])
def test_dib_request_list_json(self):
def test_image_status_json(self):
configfile = self.setup_config("node.yaml")
pool = self.useNodepool(configfile, watermark_sleep=1)
builder = self.useBuilder(configfile)
@ -155,10 +155,8 @@ class TestWebApp(tests.DBTestCase):
self.waitForImage("fake-provider", "fake-image")
self.waitForNodes('fake-label')
self.zk.submitBuildRequest("fake-image")
req = request.Request(
"http://localhost:{}/dib-request-list".format(port))
"http://localhost:{}/image-status".format(port))
req.add_header("Accept", "application/json")
f = request.urlopen(req)
@ -168,7 +166,18 @@ class TestWebApp(tests.DBTestCase):
data = f.read()
objs = json.loads(data.decode("utf8"))
self.assertDictContainsSubset({"image": "fake-image",
"state": "pending"}, objs[0])
"paused": False,
"build_request": None}, objs[0])
self.zk.submitBuildRequest("fake-image")
webapp.cache.cache.clear()
f = request.urlopen(req)
data = f.read()
objs = json.loads(data.decode("utf8"))
self.assertDictContainsSubset({"image": "fake-image",
"paused": False,
"build_request": "pending"}, objs[0])
webapp.cache.cache.clear()
with self.zk.imageBuildLock('fake-image', blocking=True, timeout=1):
@ -177,7 +186,8 @@ class TestWebApp(tests.DBTestCase):
objs = json.loads(data.decode("utf8"))
self.assertDictContainsSubset({"image": "fake-image",
"state": "building"}, objs[0])
"paused": False,
"build_request": "building"}, objs[0])
def test_node_list_json(self):
configfile = self.setup_config('node.yaml')

@ -101,8 +101,8 @@ class WebApp(threading.Thread):
results = status.image_list(zk)
elif path == '/dib-image-list':
results = status.dib_image_list(zk)
elif path == '/dib-request-list':
results = status.dib_request_list(zk)
elif path == '/image-status':
results = status.image_status(zk)
elif path == '/node-list':
results = status.node_list(zk,
node_id=params.get('node_id'))

@ -0,0 +1,7 @@
---
features:
- |
A new `image-status` command and accompanying web endpoint are
available to easily see what images have been paused via the
`image-pause` command and have pending manual build requests via
the `build-image` command.
Loading…
Cancel
Save