Add tags manipulation to API

Also fixes some checks for Metadata too since these two actions are
almost identical, and adds tags to define endpoint.
This commit is contained in:
Joshua Boniface 2021-07-13 02:17:30 -04:00
parent c0a3467b70
commit 27f1758791
3 changed files with 281 additions and 6 deletions

View File

@ -1107,6 +1107,7 @@ class API_VM_Root(Resource):
{'name': 'selector', 'choices': ('mem', 'vcpus', 'load', 'vms', 'none'), 'helptext': "A valid selector must be specified"}, {'name': 'selector', 'choices': ('mem', 'vcpus', 'load', 'vms', 'none'), 'helptext': "A valid selector must be specified"},
{'name': 'autostart'}, {'name': 'autostart'},
{'name': 'migration_method', 'choices': ('live', 'shutdown', 'none'), 'helptext': "A valid migration_method must be specified"}, {'name': 'migration_method', 'choices': ('live', 'shutdown', 'none'), 'helptext': "A valid migration_method must be specified"},
{'name': 'tags'},
{'name': 'xml', 'required': True, 'helptext': "A Libvirt XML document must be specified"}, {'name': 'xml', 'required': True, 'helptext': "A Libvirt XML document must be specified"},
]) ])
@Authenticator @Authenticator
@ -1158,6 +1159,13 @@ class API_VM_Root(Resource):
- live - live
- shutdown - shutdown
- none - none
- in: query
name: tags
type: array
required: false
description: The tag(s) of the VM
items:
type: string
responses: responses:
200: 200:
description: OK description: OK
@ -1176,7 +1184,8 @@ class API_VM_Root(Resource):
reqargs.get('limit', None), reqargs.get('limit', None),
reqargs.get('selector', 'none'), reqargs.get('selector', 'none'),
bool(strtobool(reqargs.get('autostart', 'false'))), bool(strtobool(reqargs.get('autostart', 'false'))),
reqargs.get('migration_method', 'none') reqargs.get('migration_method', 'none'),
reqargs.get('tags', [])
) )
@ -1211,6 +1220,7 @@ class API_VM_Element(Resource):
{'name': 'selector', 'choices': ('mem', 'vcpus', 'load', 'vms', 'none'), 'helptext': "A valid selector must be specified"}, {'name': 'selector', 'choices': ('mem', 'vcpus', 'load', 'vms', 'none'), 'helptext': "A valid selector must be specified"},
{'name': 'autostart'}, {'name': 'autostart'},
{'name': 'migration_method', 'choices': ('live', 'shutdown', 'none'), 'helptext': "A valid migration_method must be specified"}, {'name': 'migration_method', 'choices': ('live', 'shutdown', 'none'), 'helptext': "A valid migration_method must be specified"},
{'name': 'tags'},
{'name': 'xml', 'required': True, 'helptext': "A Libvirt XML document must be specified"}, {'name': 'xml', 'required': True, 'helptext': "A Libvirt XML document must be specified"},
]) ])
@Authenticator @Authenticator
@ -1265,6 +1275,13 @@ class API_VM_Element(Resource):
- live - live
- shutdown - shutdown
- none - none
- in: query
name: tags
type: array
required: false
description: The tag(s) of the VM
items:
type: string
responses: responses:
200: 200:
description: OK description: OK
@ -1283,7 +1300,8 @@ class API_VM_Element(Resource):
reqargs.get('limit', None), reqargs.get('limit', None),
reqargs.get('selector', 'none'), reqargs.get('selector', 'none'),
bool(strtobool(reqargs.get('autostart', 'false'))), bool(strtobool(reqargs.get('autostart', 'false'))),
reqargs.get('migration_method', 'none') reqargs.get('migration_method', 'none'),
reqargs.get('tags', [])
) )
@RequestParser([ @RequestParser([
@ -1401,7 +1419,7 @@ class API_VM_Metadata(Resource):
type: string type: string
description: The preferred migration method (live, shutdown, none) description: The preferred migration method (live, shutdown, none)
404: 404:
description: Not found description: VM not found
schema: schema:
type: object type: object
id: Message id: Message
@ -1469,6 +1487,11 @@ class API_VM_Metadata(Resource):
schema: schema:
type: object type: object
id: Message id: Message
404:
description: VM not found
schema:
type: object
id: Message
""" """
return api_helper.update_vm_meta( return api_helper.update_vm_meta(
vm, vm,
@ -1483,6 +1506,93 @@ class API_VM_Metadata(Resource):
api.add_resource(API_VM_Metadata, '/vm/<vm>/meta') api.add_resource(API_VM_Metadata, '/vm/<vm>/meta')
# /vm/<vm>/tags
class API_VM_Tags(Resource):
@Authenticator
def get(self, vm):
"""
Return the tags of {vm}
---
tags:
- vm
responses:
200:
description: OK
schema:
type: object
id: VMTags
properties:
name:
type: string
description: The name of the VM
tags:
type: array
description: The tag(s) of the VM
items:
type: string
404:
description: VM not found
schema:
type: object
id: Message
"""
return api_helper.get_vm_tags(vm)
@RequestParser([
{'name': 'action', 'choices': ('add', 'remove', 'replace'), 'helptext': "A valid action must be specified"},
{'name': 'tags'},
])
@Authenticator
def post(self, vm, reqargs):
"""
Set the tags of {vm}
---
tags:
- vm
parameters:
- in: query
name: action
type: string
required: true
description: The action to perform with the tags, either "add" to existing, "remove" from existing, or "replace" all existing
enum:
- add
- remove
- replace
- in: query
name: tags
type: array
required: true
description: The list of text tags to add/remove/replace-with
items:
type: string
responses:
200:
description: OK
schema:
type: object
id: Message
400:
description: Bad request
schema:
type: object
id: Message
404:
description: VM not found
schema:
type: object
id: Message
"""
return api_helper.update_vm_tags(
vm,
reqargs.get('action'),
reqargs.get('tags')
)
api.add_resource(API_VM_Tags, '/vm/<vm>/tags')
# /vm/<vm</state # /vm/<vm</state
class API_VM_State(Resource): class API_VM_State(Resource):
@Authenticator @Authenticator

View File

@ -433,7 +433,7 @@ def vm_list(zkhandler, node=None, state=None, limit=None, is_fuzzy=True):
@ZKConnection(config) @ZKConnection(config)
def vm_define(zkhandler, xml, node, limit, selector, autostart, migration_method): def vm_define(zkhandler, xml, node, limit, selector, autostart, migration_method, tags=[]):
""" """
Define a VM from Libvirt XML in the PVC cluster. Define a VM from Libvirt XML in the PVC cluster.
""" """
@ -444,7 +444,7 @@ def vm_define(zkhandler, xml, node, limit, selector, autostart, migration_method
except Exception as e: except Exception as e:
return {'message': 'XML is malformed or incorrect: {}'.format(e)}, 400 return {'message': 'XML is malformed or incorrect: {}'.format(e)}, 400
retflag, retdata = pvc_vm.define_vm(zkhandler, new_cfg, node, limit, selector, autostart, migration_method, profile=None) retflag, retdata = pvc_vm.define_vm(zkhandler, new_cfg, node, limit, selector, autostart, migration_method, profile=None, tags=tags)
if retflag: if retflag:
retcode = 200 retcode = 200
@ -486,6 +486,10 @@ def update_vm_meta(zkhandler, vm, limit, selector, autostart, provisioner_profil
""" """
Update metadata of a VM. Update metadata of a VM.
""" """
dom_uuid = pvc_vm.getDomainUUID(zkhandler, vm)
if not dom_uuid:
return {"message": "VM not found."}, 404
if autostart is not None: if autostart is not None:
try: try:
autostart = bool(strtobool(autostart)) autostart = bool(strtobool(autostart))
@ -505,6 +509,51 @@ def update_vm_meta(zkhandler, vm, limit, selector, autostart, provisioner_profil
return output, retcode return output, retcode
@ZKConnection(config)
def get_vm_tags(zkhandler, vm):
"""
Get the tags of a VM.
"""
dom_uuid = pvc_vm.getDomainUUID(zkhandler, vm)
if not dom_uuid:
return {"message": "VM not found."}, 404
tags = pvc_common.getDomainTags(zkhandler, dom_uuid)
retcode = 200
retdata = {
'name': vm,
'tags': tags
}
return retdata, retcode
@ZKConnection(config)
def update_vm_tags(zkhandler, vm, action, tags):
"""
Update the tags of a VM.
"""
if action not in ['add', 'remove', 'replace']:
return {"message": "Tag action must be one of 'add', 'remove', 'replace'."}, 400
dom_uuid = pvc_vm.getDomainUUID(zkhandler, vm)
if not dom_uuid:
return {"message": "VM not found."}, 404
retflag, retdata = pvc_vm.modify_vm_tags(zkhandler, vm, action, tags)
if retflag:
retcode = 200
else:
retcode = 400
output = {
'message': retdata.replace('\"', '\'')
}
return output, retcode
@ZKConnection(config) @ZKConnection(config)
def vm_modify(zkhandler, name, restart, xml): def vm_modify(zkhandler, name, restart, xml):
""" """

View File

@ -215,6 +215,22 @@
}, },
"type": "object" "type": "object"
}, },
"VMTags": {
"properties": {
"name": {
"description": "The name of the VM",
"type": "string"
},
"tags": {
"description": "The tag(s) of the VM",
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"acl": { "acl": {
"properties": { "properties": {
"description": { "description": {
@ -5889,6 +5905,16 @@
"name": "migration_method", "name": "migration_method",
"required": false, "required": false,
"type": "string" "type": "string"
},
{
"description": "The tag(s) of the VM",
"in": "query",
"items": {
"type": "string"
},
"name": "tags",
"required": false,
"type": "array"
} }
], ],
"responses": { "responses": {
@ -6027,6 +6053,16 @@
"name": "migration_method", "name": "migration_method",
"required": false, "required": false,
"type": "string" "type": "string"
},
{
"description": "The tag(s) of the VM",
"in": "query",
"items": {
"type": "string"
},
"name": "tags",
"required": false,
"type": "array"
} }
], ],
"responses": { "responses": {
@ -6151,7 +6187,7 @@
} }
}, },
"404": { "404": {
"description": "Not found", "description": "VM not found",
"schema": { "schema": {
"$ref": "#/definitions/Message" "$ref": "#/definitions/Message"
} }
@ -6225,6 +6261,12 @@
"schema": { "schema": {
"$ref": "#/definitions/Message" "$ref": "#/definitions/Message"
} }
},
"404": {
"description": "VM not found",
"schema": {
"$ref": "#/definitions/Message"
}
} }
}, },
"summary": "Set the metadata of {vm}", "summary": "Set the metadata of {vm}",
@ -6412,6 +6454,80 @@
"vm" "vm"
] ]
} }
},
"/api/v1/vm/{vm}/tags": {
"get": {
"description": "",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/VMTags"
}
},
"404": {
"description": "VM not found",
"schema": {
"$ref": "#/definitions/Message"
}
}
},
"summary": "Return the tags of {vm}",
"tags": [
"vm"
]
},
"post": {
"description": "",
"parameters": [
{
"description": "The action to perform with the tags, either \"add\" to existing, \"remove\" from existing, or \"replace\" all existing",
"enum": [
"add",
"remove",
"replace"
],
"in": "query",
"name": "action",
"required": true,
"type": "string"
},
{
"description": "The list of text tags to add/remove/replace-with",
"in": "query",
"items": {
"type": "string"
},
"name": "tags",
"required": true,
"type": "array"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/Message"
}
},
"400": {
"description": "Bad request",
"schema": {
"$ref": "#/definitions/Message"
}
},
"404": {
"description": "VM not found",
"schema": {
"$ref": "#/definitions/Message"
}
}
},
"summary": "Set the tags of {vm}",
"tags": [
"vm"
]
}
} }
}, },
"swagger": "2.0" "swagger": "2.0"