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
This commit is contained in:
parent
d6e8bd72df
commit
138b68a5a7
@ -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'))
|
||||
|
7
releasenotes/notes/image-status-bedca1dd0184c14b.yaml
Normal file
7
releasenotes/notes/image-status-bedca1dd0184c14b.yaml
Normal file
@ -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…
Reference in New Issue
Block a user