mrc0mmand / rpms / libguestfs

Forked from rpms/libguestfs 3 years ago
Clone
Blob Blame History Raw
From ccd327919ca1fed3e10fdd3567ede0dc8cd5d0c3 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Thu, 12 Sep 2019 15:21:26 +0200
Subject: [PATCH] v2v: -o rhv-upload: improve lookup of specified resources
 (RHBZ#1612653)

Improve the way the precheck script checks for the specified resources:
- look directly for a data center with the specified storage domain
- get the storage domain object from the storage domains attached to the
  data center found
- similarly, look for the specified cluster among the ones attached to
  the data center found
When everything is found, return the UUID of the storage domain, and of
the cluster back to virt-v2v, which will store them.

Similarly, rework the createvm script to directly get the requested
cluster, instead of looking for it once again.  Also, since the UUID of
the storage domain is available in virt-v2v already, use it directly
instead of using a placeholder.

This should fix a number of issues:
- unexisting/unattached storage domains are rejected outright
- the cluster is rejected if not part of the same data center of the
  selected storage domain
- renaming the specified storage domain during the data copying will not
  cause the conversion to fail (which will still use the specified
  storage domain, no matter the new name)

Based on the hints by Daniel Erez in RHBZ#1612653.

(cherry picked from commit c49aa4fe01aac82d4776dd2a3524ce16e6deed06)
---
 v2v/output_rhv_upload.ml   | 24 +++++++++++++++++++-----
 v2v/rhv-upload-createvm.py | 11 ++++-------
 v2v/rhv-upload-precheck.py | 30 ++++++++++++++++++++++++------
 3 files changed, 47 insertions(+), 18 deletions(-)

diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml
index fd6f2e3e6..19bdfcf05 100644
--- a/v2v/output_rhv_upload.ml
+++ b/v2v/output_rhv_upload.ml
@@ -227,6 +227,11 @@ See also the virt-v2v-output-rhv(1) manual.")
 object
   inherit output
 
+  (* The storage domain UUID. *)
+  val mutable rhv_storagedomain_uuid = None
+  (* The cluster UUID. *)
+  val mutable rhv_cluster_uuid = None
+
   method precheck () =
     Python_script.error_unless_python_interpreter_found ();
     error_unless_ovirtsdk4_module_available ();
@@ -242,6 +247,10 @@ object
     let json = JSON_parser.json_parser_tree_parse_file precheck_fn in
     debug "precheck output parsed as: %s"
           (JSON.string_of_doc ~fmt:JSON.Indented ["", json]);
+    rhv_storagedomain_uuid <-
+       Some (JSON_parser.object_get_string "rhv_storagedomain_uuid" json);
+    rhv_cluster_uuid <-
+       Some (JSON_parser.object_get_string "rhv_cluster_uuid" json);
     if have_selinux then
       error_unless_nbdkit_compiled_with_selinux ()
 
@@ -388,11 +397,11 @@ If the messages above are not sufficient to diagnose the problem then add the 
           diskid
       ) targets in
 
-    (* We don't have the storage domain UUID, but instead we write
-     * in a magic value which the Python code (which can get it)
-     * will substitute.
-     *)
-    let sd_uuid = "@SD_UUID@" in
+    (* The storage domain UUID. *)
+    let sd_uuid =
+      match rhv_storagedomain_uuid with
+      | None -> assert false
+      | Some uuid -> uuid in
 
     (* The volume and VM UUIDs are made up. *)
     let vol_uuids = List.map (fun _ -> uuidgen ()) targets
@@ -406,6 +415,11 @@ If the messages above are not sufficient to diagnose the problem then add the 
                             OVirt in
     let ovf = DOM.doc_to_string ovf in
 
+    let json_params =
+      match rhv_cluster_uuid with
+      | None -> assert false
+      | Some uuid -> ("rhv_cluster_uuid", JSON.String uuid) :: json_params in
+
     let ovf_file = tmpdir // "vm.ovf" in
     with_open_out ovf_file (fun chan -> output_string chan ovf);
     if Python_script.run_command createvm_script json_params [ovf_file] <> 0
diff --git a/v2v/rhv-upload-createvm.py b/v2v/rhv-upload-createvm.py
index 1d0e8c95d..ed57a9b20 100644
--- a/v2v/rhv-upload-createvm.py
+++ b/v2v/rhv-upload-createvm.py
@@ -65,17 +65,14 @@ connection = sdk.Connection(
 
 system_service = connection.system_service()
 
-# Get the storage domain UUID and substitute it into the OVF doc.
-sds_service = system_service.storage_domains_service()
-sd = sds_service.list(search=("name=%s" % params['output_storage']))[0]
-sd_uuid = sd.id
-
-ovf = ovf.replace("@SD_UUID@", sd_uuid)
+# Get the cluster.
+cluster = system_service.clusters_service().cluster_service(params['rhv_cluster_uuid'])
+cluster = cluster.get()
 
 vms_service = system_service.vms_service()
 vm = vms_service.add(
     types.Vm(
-        cluster=types.Cluster(name = params['rhv_cluster']),
+        cluster=cluster,
         initialization=types.Initialization(
             configuration = types.Configuration(
                 type = types.ConfigurationType.OVA,
diff --git a/v2v/rhv-upload-precheck.py b/v2v/rhv-upload-precheck.py
index de8a66c05..725a8dc9e 100644
--- a/v2v/rhv-upload-precheck.py
+++ b/v2v/rhv-upload-precheck.py
@@ -60,18 +60,36 @@ connection = sdk.Connection(
 
 system_service = connection.system_service()
 
-# Check whether the specified cluster exists.
-clusters_service = system_service.clusters_service()
-clusters = clusters_service.list(
-    search='name=%s' % params['rhv_cluster'],
+# Check whether there is a datacenter for the specified storage.
+data_centers = system_service.data_centers_service().list(
+    search='storage.name=%s' % params['output_storage'],
     case_sensitive=True,
 )
+if len(data_centers) == 0:
+    # The storage domain is not attached to a datacenter
+    # (shouldn't happen, would fail on disk creation).
+    raise RuntimeError("The storage domain ‘%s’ is not attached to a DC" %
+                       (params['output_storage']))
+datacenter = data_centers[0]
+
+# Get the storage domain.
+storage_domains = connection.follow_link(datacenter.storage_domains)
+storage_domain = [sd for sd in storage_domains if sd.name == params['output_storage']][0]
+
+# Get the cluster.
+clusters = connection.follow_link(datacenter.clusters)
+clusters = [cluster for cluster in clusters if cluster.name == params['rhv_cluster']]
 if len(clusters) == 0:
-    raise RuntimeError("The cluster ‘%s’ does not exist" %
-                       (params['rhv_cluster']))
+    raise RuntimeError("The cluster ‘%s’ is not part of the DC ‘%s’, "
+                       "where the storage domain ‘%s’ is" %
+                       (params['rhv_cluster'], datacenter.name,
+                        params['output_storage']))
+cluster = clusters[0]
 
 # Otherwise everything is OK, print a JSON with the results.
 results = {
+  "rhv_storagedomain_uuid": storage_domain.id,
+  "rhv_cluster_uuid": cluster.id,
 }
 
 json.dump(results, sys.stdout)
-- 
2.26.2