using stop_reason as a vdsm hook trigger into the UI

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 blanchet@abes.fr

On Mon, Dec 20, 2021 at 9:59 PM Nathanaël Blanchet <blanchet@abes.fr> wrote: Adding the devel list since question is more about extending oVirt ...
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 you want to run the clean hook only if stop reason == "clean"? I think the way to integrate hooks is to define a custom property in the vm, and check if the property was defined in the hook. For example how the localdisk hook is triggered: def main(): backend = os.environ.get('localdisk') if backend is None: return if backend not in [BACKEND_LVM, BACKEND_LVM_THIN]: hooking.log("localdisk-hook: unsupported backend: %r" % backend) return ... The hook runs only if the environment variable "localdisk" is defined and configured properly. vdsm defines the custom properties as environment variables. On the engine side, you need to add a user defined property: engine-config -s UserDefinedVMProperties='localdisk=^(lvm|lvmthin)$' And configure a custom property with one of the allowed values, like: localdisk=lvm See vdsm_hooks/localdisk/README for more info. If you want to control the cleanup, by adding a "clean" stop reason only when needed, this will not help, and vdsm hook is probably not the right way to integrate this. If your intent is to clean a vm in some special events, but you want to integrate this in engine, maybe you should write an engine ui plugin? The plugin can show the running vms, and provide a clean button that will shut down the vm and run your custom code. But maybe you don't need to integrate this in engine, and having a simple script using ovirt engine API/SDK to shutdown the vm and run the cleanup code. Nir

Thanks for responding, Le 20/12/2021 à 21:42, Nir Soffer a écrit :
On Mon, Dec 20, 2021 at 9:59 PM Nathanaël Blanchet <blanchet@abes.fr> wrote:
Adding the devel list since question is more about extending oVirt ...
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 you want to run the clean hook only if stop reason == "clean"?
I think the way to integrate hooks is to define a custom property in the vm, and check if the property was defined in the hook.
For example how the localdisk hook is triggered:
def main(): backend = os.environ.get('localdisk') if backend is None: return if backend not in [BACKEND_LVM, BACKEND_LVM_THIN]: hooking.log("localdisk-hook: unsupported backend: %r" % backend) return ...
The hook runs only if the environment variable "localdisk" is defined and configured properly.
vdsm defines the custom properties as environment variables.
On the engine side, you need to add a user defined property:
engine-config -s UserDefinedVMProperties='localdisk=^(lvm|lvmthin)$'
And configure a custom property with one of the allowed values, like:
localdisk=lvm
See vdsm_hooks/localdisk/README for more info.
If you want to control the cleanup, by adding a "clean" stop reason only when needed, this will not help, and vdsm hook is probably not the right way to integrate this. Sure
If your intent is to clean a vm in some special events, but you want to integrate this in engine, maybe you should write an engine ui plugin?
The plugin can show the running vms, and provide a clean button that will shut down the vm and run your custom code. too complex for doing what I want
But maybe you don't need to integrate this in engine, and having a simple script using ovirt engine API/SDK to shutdown the vm and run the cleanup code. My playbook/scripts work already fine, but this is not my goal. Nir
I will sum up my initial question: *Is there any way to get the value of "stop_reason" (value of the field in the UI) so as to reuse this variable into a vdsm hook?* Thank you -- 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 blanchet@abes.fr

Maybe use the events api and search for the shutdown and reason in there? api/events;from={event_id}?search={query}" rel="events/search"/> -John On Tue, Dec 21, 2021 at 9:00 AM Nathanaël Blanchet <blanchet@abes.fr> wrote:
Thanks for responding, Le 20/12/2021 à 21:42, Nir Soffer a écrit :
On Mon, Dec 20, 2021 at 9:59 PM Nathanaël Blanchet <blanchet@abes.fr> <blanchet@abes.fr> wrote:
Adding the devel list since question is more about extending oVirt ...
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 you want to run the clean hook only if stop reason == "clean"?
I think the way to integrate hooks is to define a custom property in the vm, and check if the property was defined in the hook.
For example how the localdisk hook is triggered:
def main(): backend = os.environ.get('localdisk') if backend is None: return if backend not in [BACKEND_LVM, BACKEND_LVM_THIN]: hooking.log("localdisk-hook: unsupported backend: %r" % backend) return ...
The hook runs only if the environment variable "localdisk" is defined and configured properly.
vdsm defines the custom properties as environment variables.
On the engine side, you need to add a user defined property:
engine-config -s UserDefinedVMProperties='localdisk=^(lvm|lvmthin)$'
And configure a custom property with one of the allowed values, like:
localdisk=lvm
See vdsm_hooks/localdisk/README for more info.
If you want to control the cleanup, by adding a "clean" stop reason only when needed, this will not help, and vdsm hook is probably not the right way to integrate this.
Sure
If your intent is to clean a vm in some special events, but you want to integrate this in engine, maybe you should write an engine ui plugin?
The plugin can show the running vms, and provide a clean button that will shut down the vm and run your custom code.
too complex for doing what I want
But maybe you don't need to integrate this in engine, and having a simple script using ovirt engine API/SDK to shutdown the vm and run the cleanup code.
My playbook/scripts work already fine, but this is not my goal.
Nir
I will sum up my initial question: *Is there any way to get the value of "stop_reason" (value of the field in the UI) so as to reuse this variable into a vdsm hook?*
Thank you
-- 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 14blanchet@abes.fr
_______________________________________________ Users mailing list -- users@ovirt.org To unsubscribe send an email to users-leave@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/OSM572SLKKAFOW...

Le 22/12/2021 à 14:56, John Taylor a écrit :
Maybe use the events api and search for the shutdown and reason in there?
api/events;from={event_id}?search={query}" rel="events/search"/>
-John
Exact! that's precisely the workaround I already tested this morning as well :) and it works because the event contains the stop_reason in the description field before vm is in the stopped status!
On Tue, Dec 21, 2021 at 9:00 AM Nathanaël Blanchet <blanchet@abes.fr <mailto:blanchet@abes.fr>> wrote:
Thanks for responding,
Le 20/12/2021 à 21:42, Nir Soffer a écrit :
On Mon, Dec 20, 2021 at 9:59 PM Nathanaël Blanchet<blanchet@abes.fr> <mailto:blanchet@abes.fr> wrote:
Adding the devel list since question is more about extending oVirt ...
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 you want to run the clean hook only if stop reason == "clean"?
I think the way to integrate hooks is to define a custom property in the vm, and check if the property was defined in the hook.
For example how the localdisk hook is triggered:
def main(): backend = os.environ.get('localdisk') if backend is None: return if backend not in [BACKEND_LVM, BACKEND_LVM_THIN]: hooking.log("localdisk-hook: unsupported backend: %r" % backend) return ...
The hook runs only if the environment variable "localdisk" is defined and configured properly.
vdsm defines the custom properties as environment variables.
On the engine side, you need to add a user defined property:
engine-config -s UserDefinedVMProperties='localdisk=^(lvm|lvmthin)$'
And configure a custom property with one of the allowed values, like:
localdisk=lvm
See vdsm_hooks/localdisk/README for more info.
If you want to control the cleanup, by adding a "clean" stop reason only when needed, this will not help, and vdsm hook is probably not the right way to integrate this.
Sure
If your intent is to clean a vm in some special events, but you want to integrate this in engine, maybe you should write an engine ui plugin?
The plugin can show the running vms, and provide a clean button that will shut down the vm and run your custom code.
too complex for doing what I want
But maybe you don't need to integrate this in engine, and having a simple script using ovirt engine API/SDK to shutdown the vm and run the cleanup code.
My playbook/scripts work already fine, but this is not my goal.
Nir
I will sum up my initial question: *Is there any way to get the value of "stop_reason" (value of the field in the UI) so as to reuse this variable into a vdsm hook?*
Thank you
-- 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 blanchet@abes.fr <mailto:blanchet@abes.fr>
_______________________________________________ Users mailing list -- users@ovirt.org <mailto:users@ovirt.org> To unsubscribe send an email to users-leave@ovirt.org <mailto:users-leave@ovirt.org> Privacy Statement: https://www.ovirt.org/privacy-policy.html <https://www.ovirt.org/privacy-policy.html> oVirt Code of Conduct: https://www.ovirt.org/community/about/community-guidelines/ <https://www.ovirt.org/community/about/community-guidelines/> List Archives: https://lists.ovirt.org/archives/list/users@ovirt.org/message/OSM572SLKKAFOW... <https://lists.ovirt.org/archives/list/users@ovirt.org/message/OSM572SLKKAFOWZWT6OTNSFZED5JX5RC/>
-- 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 blanchet@abes.fr

Le 22/12/2021 à 15:49, Nathanaël Blanchet a écrit :
Le 22/12/2021 à 14:56, John Taylor a écrit :
Maybe use the events api and search for the shutdown and reason in there?
api/events;from={event_id}?search={query}" rel="events/search"/>
-John
Exact! that's precisely the workaround I already tested this morning as well :)
and it works because the event contains the stop_reason in the description field before vm is in the stopped status!
Unfortunately, after some additionnal tests, I am in the same situation as initially with stop_reason element in api/vm, i.e. the new event containing the stop reason is writed to the API only after the hook script has exited. So I am never able to test this variable to determine the action to do... P.S: For those who are interested: to make that case work, I proceeded at the opposite: rather than testing the variable condition in the hook itsself, I only use the hook to curl a job_template in AWX. By this way, the hook exits, and the ovirt_vm_info returns the expected stop_reason value and so on for following actions...
On Tue, Dec 21, 2021 at 9:00 AM Nathanaël Blanchet <blanchet@abes.fr <mailto:blanchet@abes.fr>> wrote:
Thanks for responding,
Le 20/12/2021 à 21:42, Nir Soffer a écrit :
On Mon, Dec 20, 2021 at 9:59 PM Nathanaël Blanchet<blanchet@abes.fr> <mailto:blanchet@abes.fr> wrote:
Adding the devel list since question is more about extending oVirt ...
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 you want to run the clean hook only if stop reason == "clean"?
I think the way to integrate hooks is to define a custom property in the vm, and check if the property was defined in the hook.
For example how the localdisk hook is triggered:
def main(): backend = os.environ.get('localdisk') if backend is None: return if backend not in [BACKEND_LVM, BACKEND_LVM_THIN]: hooking.log("localdisk-hook: unsupported backend: %r" % backend) return ...
The hook runs only if the environment variable "localdisk" is defined and configured properly.
vdsm defines the custom properties as environment variables.
On the engine side, you need to add a user defined property:
engine-config -s UserDefinedVMProperties='localdisk=^(lvm|lvmthin)$'
And configure a custom property with one of the allowed values, like:
localdisk=lvm
See vdsm_hooks/localdisk/README for more info.
If you want to control the cleanup, by adding a "clean" stop reason only when needed, this will not help, and vdsm hook is probably not the right way to integrate this.
Sure
If your intent is to clean a vm in some special events, but you want to integrate this in engine, maybe you should write an engine ui plugin?
The plugin can show the running vms, and provide a clean button that will shut down the vm and run your custom code.
too complex for doing what I want
But maybe you don't need to integrate this in engine, and having a simple script using ovirt engine API/SDK to shutdown the vm and run the cleanup code.
My playbook/scripts work already fine, but this is not my goal.
Nir
I will sum up my initial question: *Is there any way to get the value of "stop_reason" (value of the field in the UI) so as to reuse this variable into a vdsm hook?*
Thank you
-- 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 blanchet@abes.fr <mailto:blanchet@abes.fr>
_______________________________________________ Users mailing list -- users@ovirt.org <mailto:users@ovirt.org> To unsubscribe send an email to users-leave@ovirt.org <mailto:users-leave@ovirt.org> Privacy Statement: https://www.ovirt.org/privacy-policy.html <https://www.ovirt.org/privacy-policy.html> oVirt Code of Conduct: https://www.ovirt.org/community/about/community-guidelines/ <https://www.ovirt.org/community/about/community-guidelines/> List Archives: https://lists.ovirt.org/archives/list/users@ovirt.org/message/OSM572SLKKAFOW... <https://lists.ovirt.org/archives/list/users@ovirt.org/message/OSM572SLKKAFOWZWT6OTNSFZED5JX5RC/>
-- 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 blanchet@abes.fr
_______________________________________________ Users mailing list -- users@ovirt.org To unsubscribe send an email to users-leave@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/3O3BKLSJ5PTHFW...
-- 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 blanchet@abes.fr
participants (3)
-
John Taylor
-
Nathanaël Blanchet
-
Nir Soffer