Add nodes/nodeset-requests commands

This adds the ability to list and manipulate nodes and nodeset
requests.  No release note or documentation is added since these
are related to nodepool-in-zuul which is in stealth mode.

Change-Id: Ia3e987062122e017f19376ab30d9587becedca23
This commit is contained in:
James E. Blair
2025-06-03 16:10:08 -07:00
parent 8940fb8c7e
commit 0d8e396011
3 changed files with 182 additions and 0 deletions

View File

@@ -371,3 +371,59 @@ class ZuulRESTClient(object):
req = self.session.get(url)
self._check_request_status(req)
return req.json()
def get_nodes(self, tenant):
if self.info.get('tenant'):
self._check_scope(tenant)
suffix = 'nodes'
else:
suffix = f'tenant/{tenant}/nodes'
url = urllib.parse.urljoin(
self.base_url,
suffix)
req = self.session.get(url)
self._check_request_status(req)
return req.json()
def put_node(self, tenant, node, **args):
if not self.auth_token:
raise Exception('Auth Token required')
if self.info.get('tenant'):
self._check_scope(tenant)
suffix = f'nodes/{node}'
else:
suffix = f'tenant/{tenant}/nodes/{node}'
url = urllib.parse.urljoin(
self.base_url,
suffix)
req = self.session.put(url, json=args)
self._check_request_status(req)
return req.json()
def get_nodeset_requests(self, tenant):
if self.info.get('tenant'):
self._check_scope(tenant)
suffix = 'nodeset-requests'
else:
suffix = f'tenant/{tenant}/nodeset-requests'
url = urllib.parse.urljoin(
self.base_url,
suffix)
req = self.session.get(url)
self._check_request_status(req)
return req.json()
def delete_nodeset_request(self, tenant, request):
if not self.auth_token:
raise Exception('Auth Token required')
if self.info.get('tenant'):
self._check_scope(tenant)
suffix = f'nodeset-requests/{request}'
else:
suffix = f'tenant/{tenant}/nodeset-requests/{request}'
url = urllib.parse.urljoin(
self.base_url,
suffix)
req = self.session.delete(url)
self._check_request_status(req)
return (req.status_code == 204)

View File

@@ -130,6 +130,10 @@ class ZuulClient():
self.add_build_info_subparser(subparsers)
self.add_job_graph_subparser(subparsers)
self.add_freeze_job_subparser(subparsers)
self.add_node_list_subparser(subparsers)
self.add_node_set_state_subparser(subparsers)
self.add_nodeset_request_list_subparser(subparsers)
self.add_nodeset_request_delete_subparser(subparsers)
return subparsers
@@ -556,6 +560,84 @@ class ZuulClient():
client.tenant_state(tenant, **kwargs)
return True
def add_node_list_subparser(self, subparsers):
cmd = subparsers.add_parser('node-list',
help='list nodes')
cmd.add_argument('--tenant', help='tenant name',
required=False, default='')
cmd.set_defaults(func=self.node_list)
self.cmd_node_list = cmd
def node_list(self):
client = self.get_client()
self._check_tenant_scope(client)
tenant = self.tenant()
nodes = client.get_nodes(tenant)
formatted_result = self.formatter('NodeList')(nodes)
print(formatted_result)
return True
def add_node_set_state_subparser(self, subparsers):
cmd = subparsers.add_parser('node-set-state',
help='set the state of a node')
cmd.add_argument('--tenant', help='tenant name',
required=False, default='')
cmd.add_argument('node', help='node id')
cmd.add_argument('state',
help='new node state',
choices=[
'hold',
'used',
])
cmd.set_defaults(func=self.node_set_state)
self.cmd_node_set_state = cmd
def node_set_state(self):
client = self.get_client()
self._check_tenant_scope(client)
tenant = self.tenant()
self.log.info('Setting node with arguments: %s %s',
self.args.node, self.args.state)
r = client.put_node(tenant, self.args.node, state=self.args.state)
return not r
def add_nodeset_request_list_subparser(self, subparsers):
cmd = subparsers.add_parser('nodeset-request-list',
help='list nodeset requests')
cmd.add_argument('--tenant', help='tenant name',
required=False, default='')
cmd.set_defaults(func=self.nodeset_request_list)
self.cmd_nodeset_request_list = cmd
def nodeset_request_list(self):
client = self.get_client()
self._check_tenant_scope(client)
tenant = self.tenant()
requests = client.get_nodeset_requests(tenant)
formatted_result = self.formatter('NodesetRequestList')(requests)
print(formatted_result)
return True
def add_nodeset_request_delete_subparser(self, subparsers):
cmd = subparsers.add_parser('nodeset-request-delete',
help='delete a nodeset request')
cmd.add_argument('--tenant', help='tenant name',
required=False, default='')
cmd.add_argument('request', help='nodeset request id')
cmd.set_defaults(func=self.nodeset_request_delete)
self.cmd_nodeset_request_delete = cmd
def nodeset_request_delete(self):
client = self.get_client()
self._check_tenant_scope(client)
tenant = self.tenant()
self.log.info('Deleting nodeset request: %s',
self.args.request)
r = client.delete_nodeset_request(tenant, self.args.request)
return r
def get_config_section(self):
conf_sections = self.config.sections()
if len(conf_sections) == 1 and self.args.zuul_config is None:

View File

@@ -70,6 +70,12 @@ class BaseFormatter:
def formatFreezeJob(self, data):
raise NotImplementedError
def formatNodeList(self, data):
raise NotImplementedError
def formatNodesetRequestList(self, data):
raise NotImplementedError
class JSONFormatter(BaseFormatter):
def __call__(self, data) -> str:
@@ -332,6 +338,44 @@ class PrettyTableFormatter(BaseFormatter):
ret += printer.pformat(data['vars'])
return ret
def formatNodeList(self, data) -> str:
table = prettytable.PrettyTable(
field_names=[
'UUID', 'Labels', 'Connection', 'Provider', 'State',
'State Time', 'Comment'
])
for node in data:
table.add_row([
node.get('uuid', 'N/A'),
node.get('type', 'N/A'),
node.get('connection_type', 'N/A'),
node.get('provider', 'N/A'),
node.get('state', 'N/A'),
node.get('state_time', 'N/A'),
node.get('comment', 'N/A'),
])
return str(table)
def formatNodesetRequestList(self, data) -> str:
table = prettytable.PrettyTable(
field_names=[
'UUID', 'Labels', 'State', 'Request Time', 'Buildset',
'Pipeline', 'Job'
])
for node in data:
table.add_row([
node.get('uuid', 'N/A'),
node.get('labels', 'N/A'),
node.get('state', 'N/A'),
node.get('request_time', 'N/A'),
node.get('buildset_uuid', 'N/A'),
node.get('pipeline_name', 'N/A'),
node.get('job_name', 'N/A'),
])
return str(table)
class DotFormatter(BaseFormatter):
"""Format for graphviz"""