Merge "Convert dib-request-list to image-status command"

This commit is contained in:
Zuul 2022-06-23 20:10:21 +00:00 committed by Gerrit Code Review
commit b4e9e4a52c
7 changed files with 57 additions and 31 deletions

View File

@ -149,9 +149,9 @@ dib-image-list
.. program-output:: nodepool dib-image-list --help .. program-output:: nodepool dib-image-list --help
:nostderr: :nostderr:
dib-request-list image-status
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^
.. program-output:: nodepool dib-request-list --help .. program-output:: nodepool image-status --help
:nostderr: :nostderr:
image-list image-list
@ -396,9 +396,9 @@ launchers, all will provide the same information.
:resheader Content-Type: ``application/json`` or ``text/plain`` :resheader Content-Type: ``application/json`` or ``text/plain``
depending on the :http:header:`Accept` header 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 :query fields: comma-separated list of fields to display
:reqheader Accept: ``application/json`` or ``text/*`` :reqheader Accept: ``application/json`` or ``text/*``

View File

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

View File

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

View File

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

View File

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

View File

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

View 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.