Add limit negation to VM list

When using the "state", "node", or "tag" arguments to a VM list, add
support for a "negate" flag to look for all VMs *not in* the state,
node, or tag state.
This commit is contained in:
Joshua Boniface 2021-10-07 11:13:30 -04:00
parent 761032b321
commit c0f7ba0125
6 changed files with 43 additions and 18 deletions

View File

@ -891,6 +891,7 @@ class API_VM_Root(Resource):
{'name': 'node'}, {'name': 'node'},
{'name': 'state'}, {'name': 'state'},
{'name': 'tag'}, {'name': 'tag'},
{'name': 'negate'},
]) ])
@Authenticator @Authenticator
def get(self, reqargs): def get(self, reqargs):
@ -1155,6 +1156,11 @@ class API_VM_Root(Resource):
type: string type: string
required: false required: false
description: Limit list to VMs with this tag description: Limit list to VMs with this tag
- in: query
name: negate
type: boolean
required: false
description: Negate the specified node, state, or tag limit(s)
responses: responses:
200: 200:
description: OK description: OK
@ -1164,10 +1170,11 @@ class API_VM_Root(Resource):
$ref: '#/definitions/vm' $ref: '#/definitions/vm'
""" """
return api_helper.vm_list( return api_helper.vm_list(
reqargs.get('node', None), node=reqargs.get('node', None),
reqargs.get('state', None), state=reqargs.get('state', None),
reqargs.get('tag', None), tag=reqargs.get('tag', None),
reqargs.get('limit', None) limit=reqargs.get('limit', None),
negate=bool(strtobool(reqargs.get('negate', 'False'))),
) )
@RequestParser([ @RequestParser([
@ -1297,7 +1304,7 @@ class API_VM_Element(Resource):
type: object type: object
id: Message id: Message
""" """
return api_helper.vm_list(None, None, None, vm, is_fuzzy=False) return api_helper.vm_list(node=None, state=None, tag=None, limit=vm, is_fuzzy=False, negate=False)
@RequestParser([ @RequestParser([
{'name': 'limit'}, {'name': 'limit'},

View File

@ -354,7 +354,7 @@ def vm_state(zkhandler, vm):
""" """
Return the state of virtual machine VM. Return the state of virtual machine VM.
""" """
retflag, retdata = pvc_vm.get_list(zkhandler, None, None, None, vm, is_fuzzy=False) retflag, retdata = pvc_vm.get_list(zkhandler, None, None, None, vm, is_fuzzy=False, negate=False)
if retflag: if retflag:
if retdata: if retdata:
@ -383,7 +383,7 @@ def vm_node(zkhandler, vm):
""" """
Return the current node of virtual machine VM. Return the current node of virtual machine VM.
""" """
retflag, retdata = pvc_vm.get_list(zkhandler, None, None, None, vm, is_fuzzy=False) retflag, retdata = pvc_vm.get_list(zkhandler, None, None, None, vm, is_fuzzy=False, negate=False)
if retflag: if retflag:
if retdata: if retdata:
@ -437,11 +437,11 @@ def vm_console(zkhandler, vm, lines=None):
@pvc_common.Profiler(config) @pvc_common.Profiler(config)
@ZKConnection(config) @ZKConnection(config)
def vm_list(zkhandler, node=None, state=None, tag=None, limit=None, is_fuzzy=True): def vm_list(zkhandler, node=None, state=None, tag=None, limit=None, is_fuzzy=True, negate=False):
""" """
Return a list of VMs with limit LIMIT. Return a list of VMs with limit LIMIT.
""" """
retflag, retdata = pvc_vm.get_list(zkhandler, node, state, tag, limit, is_fuzzy) retflag, retdata = pvc_vm.get_list(zkhandler, node, state, tag, limit, is_fuzzy, negate)
if retflag: if retflag:
if retdata: if retdata:
@ -880,7 +880,7 @@ def vm_flush_locks(zkhandler, vm):
""" """
Flush locks of a (stopped) VM. Flush locks of a (stopped) VM.
""" """
retflag, retdata = pvc_vm.get_list(zkhandler, None, None, None, vm, is_fuzzy=False) retflag, retdata = pvc_vm.get_list(zkhandler, None, None, None, vm, is_fuzzy=False, negate=False)
if retdata[0].get('state') not in ['stop', 'disable']: if retdata[0].get('state') not in ['stop', 'disable']:
return {"message": "VM must be stopped to flush locks"}, 400 return {"message": "VM must be stopped to flush locks"}, 400

View File

@ -54,12 +54,12 @@ def vm_info(config, vm):
return False, response.json().get('message', '') return False, response.json().get('message', '')
def vm_list(config, limit, target_node, target_state, target_tag): def vm_list(config, limit, target_node, target_state, target_tag, negate):
""" """
Get list information about VMs (limited by {limit}, {target_node}, or {target_state}) Get list information about VMs (limited by {limit}, {target_node}, or {target_state})
API endpoint: GET /api/v1/vm API endpoint: GET /api/v1/vm
API arguments: limit={limit}, node={target_node}, state={target_state}, tag={target_tag} API arguments: limit={limit}, node={target_node}, state={target_state}, tag={target_tag}, negate={negate}
API schema: [{json_data_object},{json_data_object},etc.] API schema: [{json_data_object},{json_data_object},etc.]
""" """
params = dict() params = dict()
@ -71,6 +71,7 @@ def vm_list(config, limit, target_node, target_state, target_tag):
params['state'] = target_state params['state'] = target_state
if target_tag: if target_tag:
params['tag'] = target_tag params['tag'] = target_tag
params['negate'] = negate
response = call_api(config, 'get', '/vm', params=params) response = call_api(config, 'get', '/vm', params=params)

View File

@ -1827,15 +1827,19 @@ def vm_dump(filename, domain):
'-r', '--raw', 'raw', is_flag=True, default=False, '-r', '--raw', 'raw', is_flag=True, default=False,
help='Display the raw list of VM names only.' help='Display the raw list of VM names only.'
) )
@click.option(
'-n', '--negate', 'negate', is_flag=True, default=False,
help='Negate the specified node, state, or tag limit(s).'
)
@cluster_req @cluster_req
def vm_list(target_node, target_state, target_tag, limit, raw): def vm_list(target_node, target_state, target_tag, limit, raw, negate):
""" """
List all virtual machines; optionally only match names or full UUIDs matching regex LIMIT. List all virtual machines; optionally only match names or full UUIDs matching regex LIMIT.
NOTE: Red-coloured network lists indicate one or more configured networks are missing/invalid. NOTE: Red-coloured network lists indicate one or more configured networks are missing/invalid.
""" """
retcode, retdata = pvc_vm.vm_list(config, limit, target_node, target_state, target_tag) retcode, retdata = pvc_vm.vm_list(config, limit, target_node, target_state, target_tag, negate)
if retcode: if retcode:
retdata = pvc_vm.format_list(config, retdata, raw) retdata = pvc_vm.format_list(config, retdata, raw)
else: else:

View File

@ -975,7 +975,7 @@ def get_info(zkhandler, domain):
return True, domain_information return True, domain_information
def get_list(zkhandler, node, state, tag, limit, is_fuzzy=True): def get_list(zkhandler, node, state, tag, limit, is_fuzzy=True, negate=False):
if node: if node:
# Verify node is valid # Verify node is valid
if not common.verifyNode(zkhandler, node): if not common.verifyNode(zkhandler, node):
@ -1032,7 +1032,9 @@ def get_list(zkhandler, node, state, tag, limit, is_fuzzy=True):
if tag: if tag:
vm_tags = zkhandler.children(('domain.meta.tags', vm)) vm_tags = zkhandler.children(('domain.meta.tags', vm))
if tag in vm_tags: if negate and tag not in vm_tags:
is_tag_match = True
if not negate and tag in vm_tags:
is_tag_match = True is_tag_match = True
else: else:
is_tag_match = True is_tag_match = True
@ -1040,7 +1042,9 @@ def get_list(zkhandler, node, state, tag, limit, is_fuzzy=True):
# Check on node # Check on node
if node: if node:
vm_node = zkhandler.read(('domain.node', vm)) vm_node = zkhandler.read(('domain.node', vm))
if vm_node == node: if negate and vm_node != node:
is_node_match = True
if not negate and vm_node == node:
is_node_match = True is_node_match = True
else: else:
is_node_match = True is_node_match = True
@ -1048,7 +1052,9 @@ def get_list(zkhandler, node, state, tag, limit, is_fuzzy=True):
# Check on state # Check on state
if state: if state:
vm_state = zkhandler.read(('domain.state', vm)) vm_state = zkhandler.read(('domain.state', vm))
if vm_state == state: if negate and vm_state != state:
is_state_match = True
if not negate and vm_state == state:
is_state_match = True is_state_match = True
else: else:
is_state_match = True is_state_match = True

View File

@ -5971,6 +5971,13 @@
"name": "tag", "name": "tag",
"required": false, "required": false,
"type": "string" "type": "string"
},
{
"description": "Negate the specified node, state, or tag limit(s)",
"in": "query",
"name": "negate",
"required": false,
"type": "boolean"
} }
], ],
"responses": { "responses": {