In case the whole conversion fails, run a new Python script to cleanup all the uploaded (and finalized) disks. --- v2v/Makefile.am | 6 ++ v2v/output_rhv_upload.ml | 29 +++++++- v2v/output_rhv_upload_deletedisks_source.mli | 19 ++++++ v2v/rhv-upload-deletedisks.py | 71 ++++++++++++++++++++ 4 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 v2v/output_rhv_upload_deletedisks_source.mli create mode 100644 v2v/rhv-upload-deletedisks.py diff --git a/v2v/Makefile.am b/v2v/Makefile.am index 067e11049..84b56d259 100644 --- a/v2v/Makefile.am +++ b/v2v/Makefile.am @@ -25,6 +25,7 @@ BUILT_SOURCES = \ $(generator_built) \ config.ml \ output_rhv_upload_createvm_source.ml \ + output_rhv_upload_deletedisks_source.ml \ output_rhv_upload_plugin_source.ml \ output_rhv_upload_precheck_source.ml \ output_rhv_upload_vmcheck_source.ml @@ -35,6 +36,7 @@ EXTRA_DIST = \ copy_to_local.mli \ embed.sh \ rhv-upload-createvm.py \ + rhv-upload-deletedisks.py \ rhv-upload-plugin.py \ rhv-upload-precheck.py \ rhv-upload-vmcheck.py \ @@ -88,6 +90,7 @@ SOURCES_MLI = \ output_rhv.mli \ output_rhv_upload.mli \ output_rhv_upload_createvm_source.mli \ + output_rhv_upload_deletedisks_source.mli \ output_rhv_upload_plugin_source.mli \ output_rhv_upload_precheck_source.mli \ output_rhv_upload_vmcheck_source.mli \ @@ -154,6 +157,7 @@ SOURCES_ML = \ output_qemu.ml \ output_rhv.ml \ output_rhv_upload_createvm_source.ml \ + output_rhv_upload_deletedisks_source.ml \ output_rhv_upload_plugin_source.ml \ output_rhv_upload_precheck_source.ml \ output_rhv_upload_vmcheck_source.ml \ @@ -173,6 +177,8 @@ SOURCES_C = \ # These files are generated and contain *.py embedded as an OCaml string. output_rhv_upload_createvm_source.ml: $(srcdir)/rhv-upload-createvm.py $(srcdir)/embed.sh code $^ $@ +output_rhv_upload_deletedisks_source.ml: $(srcdir)/rhv-upload-deletedisks.py + $(srcdir)/embed.sh code $^ $@ output_rhv_upload_plugin_source.ml: $(srcdir)/rhv-upload-plugin.py $(srcdir)/embed.sh code $^ $@ output_rhv_upload_precheck_source.ml: $(srcdir)/rhv-upload-precheck.py diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml index 0952af188..89d8e9612 100644 --- a/v2v/output_rhv_upload.ml +++ b/v2v/output_rhv_upload.ml @@ -107,6 +107,9 @@ class output_rhv_upload output_alloc output_conn let createvm_script = Python_script.create ~name:"rhv-upload-createvm.py" Output_rhv_upload_createvm_source.code in + let deletedisks_script = + Python_script.create ~name:"rhv-upload-deletedisks.py" + Output_rhv_upload_deletedisks_source.code in (* Check that the 'ovirtsdk4' Python module is available. *) let error_unless_ovirtsdk4_module_available () = @@ -220,6 +223,18 @@ See also the virt-v2v-output-rhv(1) manual.") else args in args in + (* Delete disks. + * + * This ignores errors since the only time we are doing this is on + * the failure path. + *) + let delete_disks uuids = + let ids = List.map (fun uuid -> JSON.String uuid) uuids in + let json_params = + ("disk_uuids", JSON.List ids) :: json_params in + ignore (Python_script.run_command deletedisks_script json_params []) + in + object inherit output @@ -275,6 +290,13 @@ object if Python_script.run_command vmcheck_script json_params [] <> 0 then error (f_"failed vmchecks, see earlier errors"); + (* Set up an at-exit handler so we delete the orphan disks on failure. *) + at_exit ( + fun () -> + if disks_uuids <> [] then + delete_disks disks_uuids + ); + (* Create an nbdkit instance for each disk and set the * target URI to point to the NBD socket. *) @@ -419,7 +441,12 @@ If the messages above are not sufficient to diagnose the problem then add the with_open_out ovf_file (fun chan -> output_string chan ovf); if Python_script.run_command createvm_script json_params [ovf_file] <> 0 then - error (f_"failed to create virtual machine, see earlier errors") + error (f_"failed to create virtual machine, see earlier errors"); + + (* The virtual machine was created successfully, so there are no disks + * to remove manually. + *) + disks_uuids <- [] end diff --git a/v2v/output_rhv_upload_deletedisks_source.mli b/v2v/output_rhv_upload_deletedisks_source.mli new file mode 100644 index 000000000..c1bafa15b --- /dev/null +++ b/v2v/output_rhv_upload_deletedisks_source.mli @@ -0,0 +1,19 @@ +(* virt-v2v + * Copyright (C) 2018 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + *) + +val code : string diff --git a/v2v/rhv-upload-deletedisks.py b/v2v/rhv-upload-deletedisks.py new file mode 100644 index 000000000..7e6c819f8 --- /dev/null +++ b/v2v/rhv-upload-deletedisks.py @@ -0,0 +1,71 @@ +# -*- python -*- +# oVirt or RHV upload create VM used by ‘virt-v2v -o rhv-upload’ +# Copyright (C) 2018 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import json +import logging +import sys +import time + +from http.client import HTTPSConnection +from urllib.parse import urlparse + +import ovirtsdk4 as sdk +import ovirtsdk4.types as types + +# Parameters are passed in via a JSON doc from the OCaml code. +# Because this Python code ships embedded inside virt-v2v there +# is no formal API here. +params = None + +if len(sys.argv) != 2: + raise RuntimeError("incorrect number of parameters") + +# Parameters are passed in via a JSON document. +with open(sys.argv[1], 'r') as fp: + params = json.load(fp) + +# What is passed in is a password file, read the actual password. +with open(params['output_password'], 'r') as fp: + output_password = fp.read() +output_password = output_password.rstrip() + +# Parse out the username from the output_conn URL. +parsed = urlparse(params['output_conn']) +username = parsed.username or "admin@internal" + +# Connect to the server. +connection = sdk.Connection( + url = params['output_conn'], + username = username, + password = output_password, + ca_file = params['rhv_cafile'], + log = logging.getLogger(), + insecure = params['insecure'], +) + +system_service = connection.system_service() +disks_service = system_service.disks_service() + +for uuid in params['disk_uuids']: + # Try to get and remove the disk, however do not fail + # if it does not exist (maybe removed in the meanwhile). + try: + disk_service = disks_service.disk_service(uuid) + disk_service.remove() + except sdk.NotFoundError: + pass -- 2.21.0