Hello,

I'm writing some code to make the following workflow:

 * setting a custom stop_reason as 'force_delete' when
   stopping/deleting a vm
 * this will trigger a vdsm hook into after_vm_destroy event.
 * this hook will call back AWX/ansible to:
     o remove DNS entries
     o remove vm file backup
     o delete supervision
     o (optionnal) delete the vm
 * the vm is destroyed and removed by vdsm.

Here is the code (I'm not a python expert)

#!/usr/libexec/platform-python
# 211217 NBT
# This is a vdsm hook that aims to auto delete oVirt dependencies when removing a VM directly from engine. # It is triggered when filling the stop_reason field in oVirt with strict 'clean'.
# It initially concerns following actions:
# - Centreon subscription Removing
# - Backup erase from Sotora
# - DNS cleaning on Lilas
# - IPA deletion
# This set of actions can be extended into the concerned AWX job_template (180 or 160)
# When finished, vm can be manually removed from Engine.
# When string is 'force_delete' or 'force_remove', then in addition, the vm will be automatically erased at the same time.
importos
fromvdsm.hook importhooking
fromxml.dom importminidom
importrequests
fromxml.etree importElementTree
importsys
importurllib3
importtime
importtraceback
importsubprocess
fromsubprocess importPIPE, STDOUT
importlogging
urllib3.disable_warnings()
logger = logging.getLogger("register_migration")
defexec_cmd(*args):
retcode, out, err = hooking.execCmd(args, sudo=True)
ifretcode != 0:
raiseRuntimeError("Failed to execute %s, due to: %s"%
(args, err))
returnout
if__name__== '__main__':
logging.basicConfig(filename="/var/log/vdsm/custom_hooks.log",
level=logging.INFO, format='%(asctime)s%(levelname)s%(name)s:%(message)s',
datefmt= '%Y-%m-%d%H:%M:%S')
iflen(sys.argv) > 1:
vm_name= sys.argv[1]
else:
domxml = hooking.read_domxml()
vm_name = domxml.getElementsByTagName('name')[0].firstChild.nodeValue
print(vm_name)
# API oVirt: Initialize variables
user = 'admin@internal'
password = 'password'
url = "https://air-dev.v100.abes.fr/ovirt-engine/api/vms?search=name%3D"+ vm_name
headers = {'Accept': 'application/xml'}
print('name: '+ vm_name)
# API oVirt: Test if VM stop_reason has been defined
whileTrue:
# r = requests.get(url, headers=headers, auth=('admin@internal', 'password'), verify=False)
# tree = ElementTree.fromstring(r.content)
r = exec_cmd('curl', '--insecure', '--header', 'Accept: application/xml', '--user', 'admin@internal:password', 'https://air-dev.v100.abes.fr/ovirt-engine/api/vms?search=name%3D'+ vm_name)
tree = ElementTree.fromstring(b''.join(r))
forvm intree.findall('vm'):
status = vm.find('status')
stop_reason = vm.find('stop_reason')
print(status.text)
ifstop_reason isnotNone:
print(status.text, stop_reason.text)
break
time.sleep(1)
forvm intree.findall('vm'):
stop_reason = vm.find('stop_reason')
ifstop_reason isNone:
exit('stop_reason is not defined')
else:
# API AWX: Initialize variables
header1 = 'Content-Type: application/json'
header2 = 'Authorization: Bearer token'
curl_server = "nbt"
curl_extra_vars = "{\\\"comment\\\": \\\"Nbt\\\", \\\"survey_ovirt_password\\\": \\\"password\\\", \\\"force_erase\\\": \\\"yes\\\", \\\"survey_vms_list\\\": %s}"% (vm_name)
curl_config = '{"extra_vars": "%s"}'% (curl_extra_vars)
ifstop_reason in["clean"]:
curl_job_template = "180"
print('Cleaning'+ vm_name + 'from oVirt on ancolie-'+ curl_server + 'with workflow_job_template '+ curl_job_template) curl_url = "http://ancolie-{}.v106.abes.fr/api/v2/workflow_job_templates/{}/launch/".format(curl_server,curl_job_template) exec_cmd('curl', '-f', '-H', header1, '-H', header2, '-XPOST', '-d', curl_config, curl_url)
elifstop_reason in["force_delete", "force_remove"]:
curl_job_template = "160"
print('Deleting and cleaning'+ vm_name + 'from oVirt on ancolie-'+ curl_server + 'with workflow_job_template '+ curl_job_template ) curl_url = "http://ancolie-{}.v106.abes.fr/api/v2/workflow_job_templates/{}/launch/".format(curl_server,curl_job_template) exec_cmd('curl', '-f', '-H', header1, '-H', header2, '-XPOST', '-d', curl_config, curl_url)
else:
exit('Stop reason is '+ stop_reason + ' and there is no reason to do anything for '+ vm_name)

The idea is to use the stop_reason element into the vm xml definition. But after hours, I realized that this element is writed to the vm definition file only after the VM has been destroyed.

So if I test this value (if existing) when executing the hook, the text value doesn't still exist at early time

I added a 'while' loop to wait for the stop_reason element to be present, but vdsm hangs out because of an infinity loop:

2021-12-20 18:13:30,148+0100 INFO  (jsonrpc/7) [root] /usr/libexec/vdsm/hooks/after_vm_destroy/clean_vm_dependencies_2.py: rc=1 err=b'Traceback (most recent call last):\n  File "/usr/libexec/vdsm/hooks/after_vm_destroy/clean_vm_dependencies_2.py", line 84, in <module>\n    print(status.text, stop_reason.text)\nAttributeError: \'NoneType\' object has no attribute \'text\'\n' (hooks:122)

....

So I'm deducing I'm not able to accomplish my initial goal to use stop_reason as a trigger with after_vm_destroy event.

I searched an other way to do: I thought of replacing querying ovirt API with getting the value coming from the UI, but I can't find the suitable database query. Is there a way to do such a thing? Does engine hooks exist for stopped vm??

Thank you for your help.

PS: I'm already able to do this from ansible/AWX, but I have to do it from UI/vdsm for any reason.

--
Nathanaël Blanchet

Supervision réseau
SIRE
227 avenue Professeur-Jean-Louis-Viala
34193 MONTPELLIER CEDEX 5       
Tél. 33 (0)4 67 54 84 55
Fax  33 (0)4 67 54 84 14
blanc...@abes.fr

_______________________________________________
Users mailing list -- users@ovirt.org
To unsubscribe send an email to users-le...@ovirt.org
Privacy Statement: https://www.ovirt.org/privacy-policy.html
oVirt Code of Conduct: 
https://www.ovirt.org/community/about/community-guidelines/
List Archives: 
https://lists.ovirt.org/archives/list/users@ovirt.org/message/S42J27JTR57YUEDH56B2H6AWUJS4BQFR/

Reply via email to