[Libguestfs] [PATCH] v2v: Preserve VM Generation ID (RHBZ#1598350).

Richard W.M. Jones
Thu, 05 Jul 2018 13:43:27 -0000

virt-v2v moves guests, it doesn't clone them.  Therefore we should try
to preserve the VM Generation ID (genid) as much as possible.

This has the ability to read the genid from VMware VMX files and
libvirt XML (but note RHBZ#1598348).  It can also write the genid to
libvirt (‘-o libvirt’, ‘-o local’) and QEMU (‘-o qemu’).

We are missing support currently for all OVF-based formats (hence
‘-i ova’, and all oVirt/RHV output modes).  It's unclear where we
would store the genid in this format.
---
 v2v/create_libvirt_xml.ml               |  5 +++++
 v2v/input_disk.ml                       |  1 +
 v2v/input_ova.ml                        |  1 +
 v2v/input_vmx.ml                        | 22 ++++++++++++++++++++++
 v2v/output_qemu.ml                      |  7 +++++++
 v2v/parse_libvirt_xml.ml                |  5 +++++
 v2v/test-v2v-i-ova-formats.expected     |  1 +
 v2v/test-v2v-i-ova-gz.expected          |  1 +
 v2v/test-v2v-i-ova-snapshots.expected   |  1 +
 v2v/test-v2v-i-ova-snapshots.expected2  |  1 +
 v2v/test-v2v-i-ova-subfolders.expected  |  1 +
 v2v/test-v2v-i-ova-subfolders.expected2 |  1 +
 v2v/test-v2v-i-ova-tar.expected         |  1 +
 v2v/test-v2v-i-ova-tar.expected2        |  1 +
 v2v/test-v2v-i-ova-two-disks.expected   |  1 +
 v2v/test-v2v-i-ova-two-disks.expected2  |  1 +
 v2v/test-v2v-i-vmx-1.expected           |  1 +
 v2v/test-v2v-i-vmx-2.expected           |  1 +
 v2v/test-v2v-i-vmx-3.expected           |  1 +
 v2v/test-v2v-i-vmx-4.expected           |  1 +
 v2v/test-v2v-i-vmx-5.expected           |  1 +
 v2v/test-v2v-print-source.expected      |  1 +
 v2v/types.ml                            |  3 +++
 v2v/types.mli                           |  1 +
 24 files changed, 61 insertions(+)

diff --git a/v2v/create_libvirt_xml.ml b/v2v/create_libvirt_xml.ml
index f5603db99..b9b248311 100644
--- a/v2v/create_libvirt_xml.ml
+++ b/v2v/create_libvirt_xml.ml
@@ -40,6 +40,11 @@ let create_libvirt_xml ?pool source target_buses guestcaps
     e "name" [] [PCData source.s_name];
   ];

+  (match source.s_genid with
+   | None -> ()
+   | Some genid -> List.push_back body (e "genid" [] [PCData
genid])
+  );
+
   let memory_k = source.s_memory /^ 1024L in
   List.push_back_list body [
     e "memory" ["unit", "KiB"] [PCData
(Int64.to_string memory_k)];
diff --git a/v2v/input_disk.ml b/v2v/input_disk.ml
index 624644532..43b901a88 100644
--- a/v2v/input_disk.ml
+++ b/v2v/input_disk.ml
@@ -80,6 +80,7 @@ class input_disk input_format disk = object
     let source = {
       s_hypervisor = UnknownHV;
       s_name = name; s_orig_name = name;
+      s_genid = None;
       s_memory = 2048L *^ 1024L *^ 1024L; (* 2048 MB *)
       s_vcpu = 1;                         (* 1 vCPU is a safe default *)
       s_cpu_vendor = None;
diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml
index c4711f902..bfd72dee4 100644
--- a/v2v/input_ova.ml
+++ b/v2v/input_ova.ml
@@ -189,6 +189,7 @@ class input_ova ova = object
       s_hypervisor = VMware;
       s_name = name;
       s_orig_name = name;
+      s_genid = None; (* XXX *)
       s_memory = memory;
       s_vcpu = vcpu;
       s_cpu_vendor = None;
diff --git a/v2v/input_vmx.ml b/v2v/input_vmx.ml
index 1a8015545..a5caf906b 100644
--- a/v2v/input_vmx.ml
+++ b/v2v/input_vmx.ml
@@ -426,6 +426,27 @@ object
          | File filename -> name_from_disk filename
          | SSH uri -> name_from_disk (path_of_uri uri) in

+    let genid +      (* XXX NOT yet tested against VMware. *)
+      let genid = Parse_vmx.get_int64 vmx ["vm"; "genid"]
+      and genidX = Parse_vmx.get_int64 vmx ["vm"; "genidX"]
in
+      match genid, genidX with
+      | None, None | Some _, None | None, Some _ -> None
+      | Some lo, Some hi ->
+         (* The actual mapping from the two integers to the UUID
+          * (as defined by qemu and used by libvirt) is very complex.
+          * This code was determined empirically.  See also:
+          *
https://lists.nongnu.org/archive/html/qemu-devel/2018-07/msg01505.html
+          *)
+         let sub = String.sub (sprintf "%016Lx%016Lx" lo hi) in
+         let uuid +           sub  8 8 ^ "-" ^
+           sub  4 4 ^ "-" ^
+           sub  0 4 ^ "-" ^
+           sub 30 2 ^ sub 28 2 ^ "-" ^
+           sub 26 2 ^ sub 24 2 ^ sub 22 2 ^ sub 20 2 ^ sub 18 2 ^ sub 16 2 in
+         Some uuid in
+
     let memory_mb        match Parse_vmx.get_int64 vmx ["memSize"]
with
       | None -> 32_L            (* default is really 32 MB! *)
@@ -483,6 +504,7 @@ object
     let source = {
       s_hypervisor = VMware;
       s_name = name;
+      s_genid = genid;
       s_orig_name = name;
       s_memory = memory;
       s_vcpu = vcpu;
diff --git a/v2v/output_qemu.ml b/v2v/output_qemu.ml
index 487363520..63b411085 100644
--- a/v2v/output_qemu.ml
+++ b/v2v/output_qemu.ml
@@ -82,6 +82,13 @@ object

     flag "-no-user-config"; flag "-nodefaults";
     arg "-name" source.s_name;
+
+    (match source.s_genid with
+     | None -> ()
+     | Some genid ->
+        arg_list "-device" ["vmgenid"; sprintf
"guid=%s" genid; "id=vmgenid0"]
+    );
+
     arg_list "-machine" (machine ::
                          (if smm then ["smm=on"] else []) @
                          ["accel=kvm:tcg"]);
diff --git a/v2v/parse_libvirt_xml.ml b/v2v/parse_libvirt_xml.ml
index cf6593043..36d2f66dd 100644
--- a/v2v/parse_libvirt_xml.ml
+++ b/v2v/parse_libvirt_xml.ml
@@ -90,6 +90,10 @@ let parse_libvirt_xml ?conn xml      | None | Some
"" ->
        error (f_"in the libvirt XML metadata, <name> is missing or
empty")
     | Some s -> s in
+  let genid +    match xpath_string "/domain/genid/text()" with
+    | None | Some "" -> None
+    | Some _ as s -> s in
   let memory      Option.default (1024L *^ 1024L) (xpath_int64
"/domain/memory/text()") in
   let memory = memory *^ 1024L in
@@ -481,6 +485,7 @@ let parse_libvirt_xml ?conn xml    ({
     s_hypervisor = hypervisor;
     s_name = name; s_orig_name = name;
+    s_genid = genid;
     s_memory = memory;
     s_vcpu = vcpu;
     s_cpu_vendor = cpu_vendor;
diff --git a/v2v/test-v2v-i-ova-formats.expected
b/v2v/test-v2v-i-ova-formats.expected
index 97bce58ad..697eaae51 100644
--- a/v2v/test-v2v-i-ova-formats.expected
+++ b/v2v/test-v2v-i-ova-formats.expected
@@ -2,6 +2,7 @@ Source guest information (--print-source option):

     source name: 2K8R2EESP1_2_Medium
 hypervisor type: vmware
+       VM genid:
          memory: 1073741824 (bytes)
        nr vCPUs: 1
      CPU vendor:
diff --git a/v2v/test-v2v-i-ova-gz.expected b/v2v/test-v2v-i-ova-gz.expected
index f1f79e309..ec2610007 100644
--- a/v2v/test-v2v-i-ova-gz.expected
+++ b/v2v/test-v2v-i-ova-gz.expected
@@ -2,6 +2,7 @@ Source guest information (--print-source option):

     source name: 2K8R2EESP1_2_Medium
 hypervisor type: vmware
+       VM genid:
          memory: 1073741824 (bytes)
        nr vCPUs: 1
      CPU vendor:
diff --git a/v2v/test-v2v-i-ova-snapshots.expected
b/v2v/test-v2v-i-ova-snapshots.expected
index a64843b35..8908de03b 100644
--- a/v2v/test-v2v-i-ova-snapshots.expected
+++ b/v2v/test-v2v-i-ova-snapshots.expected
@@ -2,6 +2,7 @@ Source guest information (--print-source option):

     source name: 2K8R2EESP1_2_Medium
 hypervisor type: vmware
+       VM genid:
          memory: 1073741824 (bytes)
        nr vCPUs: 1
      CPU vendor:
diff --git a/v2v/test-v2v-i-ova-snapshots.expected2
b/v2v/test-v2v-i-ova-snapshots.expected2
index 45be3cc46..58e985940 100644
--- a/v2v/test-v2v-i-ova-snapshots.expected2
+++ b/v2v/test-v2v-i-ova-snapshots.expected2
@@ -2,6 +2,7 @@ Source guest information (--print-source option):

     source name: 2K8R2EESP1_2_Medium
 hypervisor type: vmware
+       VM genid:
          memory: 1073741824 (bytes)
        nr vCPUs: 1
      CPU vendor:
diff --git a/v2v/test-v2v-i-ova-subfolders.expected
b/v2v/test-v2v-i-ova-subfolders.expected
index 701458b8c..6e40297d5 100644
--- a/v2v/test-v2v-i-ova-subfolders.expected
+++ b/v2v/test-v2v-i-ova-subfolders.expected
@@ -2,6 +2,7 @@ Source guest information (--print-source option):

     source name: 2K8R2EESP1_2_Medium
 hypervisor type: vmware
+       VM genid:
          memory: 1073741824 (bytes)
        nr vCPUs: 1
      CPU vendor:
diff --git a/v2v/test-v2v-i-ova-subfolders.expected2
b/v2v/test-v2v-i-ova-subfolders.expected2
index 8be8d5615..e0dd1937d 100644
--- a/v2v/test-v2v-i-ova-subfolders.expected2
+++ b/v2v/test-v2v-i-ova-subfolders.expected2
@@ -2,6 +2,7 @@ Source guest information (--print-source option):

     source name: 2K8R2EESP1_2_Medium
 hypervisor type: vmware
+       VM genid:
          memory: 1073741824 (bytes)
        nr vCPUs: 1
      CPU vendor:
diff --git a/v2v/test-v2v-i-ova-tar.expected b/v2v/test-v2v-i-ova-tar.expected
index 97bce58ad..697eaae51 100644
--- a/v2v/test-v2v-i-ova-tar.expected
+++ b/v2v/test-v2v-i-ova-tar.expected
@@ -2,6 +2,7 @@ Source guest information (--print-source option):

     source name: 2K8R2EESP1_2_Medium
 hypervisor type: vmware
+       VM genid:
          memory: 1073741824 (bytes)
        nr vCPUs: 1
      CPU vendor:
diff --git a/v2v/test-v2v-i-ova-tar.expected2 b/v2v/test-v2v-i-ova-tar.expected2
index 7f3559339..1fa120b99 100644
--- a/v2v/test-v2v-i-ova-tar.expected2
+++ b/v2v/test-v2v-i-ova-tar.expected2
@@ -2,6 +2,7 @@ Source guest information (--print-source option):

     source name: 2K8R2EESP1_2_Medium
 hypervisor type: vmware
+       VM genid:
          memory: 1073741824 (bytes)
        nr vCPUs: 1
      CPU vendor:
diff --git a/v2v/test-v2v-i-ova-two-disks.expected
b/v2v/test-v2v-i-ova-two-disks.expected
index a21153f3f..1bd23af67 100644
--- a/v2v/test-v2v-i-ova-two-disks.expected
+++ b/v2v/test-v2v-i-ova-two-disks.expected
@@ -2,6 +2,7 @@ Source guest information (--print-source option):

     source name: 2K8R2EESP1_2_Medium
 hypervisor type: vmware
+       VM genid:
          memory: 1073741824 (bytes)
        nr vCPUs: 1
      CPU vendor:
diff --git a/v2v/test-v2v-i-ova-two-disks.expected2
b/v2v/test-v2v-i-ova-two-disks.expected2
index 5f0df0625..92728ab6a 100644
--- a/v2v/test-v2v-i-ova-two-disks.expected2
+++ b/v2v/test-v2v-i-ova-two-disks.expected2
@@ -2,6 +2,7 @@ Source guest information (--print-source option):

     source name: 2K8R2EESP1_2_Medium
 hypervisor type: vmware
+       VM genid:
          memory: 1073741824 (bytes)
        nr vCPUs: 1
      CPU vendor:
diff --git a/v2v/test-v2v-i-vmx-1.expected b/v2v/test-v2v-i-vmx-1.expected
index 3314021ad..628abb450 100644
--- a/v2v/test-v2v-i-vmx-1.expected
+++ b/v2v/test-v2v-i-vmx-1.expected
@@ -3,6 +3,7 @@ Source guest information (--print-source option):

     source name: BZ1308535_21disks
 hypervisor type: vmware
+       VM genid:
          memory: 2147483648 (bytes)
        nr vCPUs: 1
      CPU vendor:
diff --git a/v2v/test-v2v-i-vmx-2.expected b/v2v/test-v2v-i-vmx-2.expected
index d7fbafb68..60fc7bd1d 100644
--- a/v2v/test-v2v-i-vmx-2.expected
+++ b/v2v/test-v2v-i-vmx-2.expected
@@ -3,6 +3,7 @@ Source guest information (--print-source option):

     source name: Fedora 20
 hypervisor type: vmware
+       VM genid:
          memory: 2147483648 (bytes)
        nr vCPUs: 1
      CPU vendor:
diff --git a/v2v/test-v2v-i-vmx-3.expected b/v2v/test-v2v-i-vmx-3.expected
index b4dcc6283..beaf8ee59 100644
--- a/v2v/test-v2v-i-vmx-3.expected
+++ b/v2v/test-v2v-i-vmx-3.expected
@@ -3,6 +3,7 @@ Source guest information (--print-source option):

     source name: RHEL 7.1 UEFI
 hypervisor type: vmware
+       VM genid:
          memory: 2147483648 (bytes)
        nr vCPUs: 1
      CPU vendor:
diff --git a/v2v/test-v2v-i-vmx-4.expected b/v2v/test-v2v-i-vmx-4.expected
index 5c45fca8d..fc60d1f1f 100644
--- a/v2v/test-v2v-i-vmx-4.expected
+++ b/v2v/test-v2v-i-vmx-4.expected
@@ -3,6 +3,7 @@ Source guest information (--print-source option):

     source name: Windows 7 x64
 hypervisor type: vmware
+       VM genid:
          memory: 2147483648 (bytes)
        nr vCPUs: 1
      CPU vendor:
diff --git a/v2v/test-v2v-i-vmx-5.expected b/v2v/test-v2v-i-vmx-5.expected
index f94306536..1b2e9dfad 100644
--- a/v2v/test-v2v-i-vmx-5.expected
+++ b/v2v/test-v2v-i-vmx-5.expected
@@ -3,6 +3,7 @@ Source guest information (--print-source option):

     source name: MSEdge - Win10_preview
 hypervisor type: vmware
+       VM genid: 8312995e-57b8-f814-4013-c1ba795f05ba
          memory: 2147483648 (bytes)
        nr vCPUs: 1
      CPU vendor:
diff --git a/v2v/test-v2v-print-source.expected
b/v2v/test-v2v-print-source.expected
index 22e88b03c..76076c719 100644
--- a/v2v/test-v2v-print-source.expected
+++ b/v2v/test-v2v-print-source.expected
@@ -1,5 +1,6 @@
     source name: windows
 hypervisor type: kvm
+       VM genid:
          memory: 1073741824 (bytes)
        nr vCPUs: 64
      CPU vendor: Intel
diff --git a/v2v/types.ml b/v2v/types.ml
index 672c8bf97..900275834 100644
--- a/v2v/types.ml
+++ b/v2v/types.ml
@@ -28,6 +28,7 @@ type source = {
   s_hypervisor : source_hypervisor;
   s_name : string;
   s_orig_name : string;
+  s_genid : string option;
   s_memory : int64;
   s_vcpu : int;
   s_cpu_vendor : string option;
@@ -109,6 +110,7 @@ and source_cpu_topology = {
 let rec string_of_source s    sprintf "    source name: %s
 hypervisor type: %s
+       VM genid: %s
          memory: %Ld (bytes)
        nr vCPUs: %d
      CPU vendor: %s
@@ -128,6 +130,7 @@ NICs:
 "
     s.s_name
     (string_of_source_hypervisor s.s_hypervisor)
+    (Option.default "" s.s_genid)
     s.s_memory
     s.s_vcpu
     (Option.default "" s.s_cpu_vendor)
diff --git a/v2v/types.mli b/v2v/types.mli
index 2bc29fa68..71788a53f 100644
--- a/v2v/types.mli
+++ b/v2v/types.mli
@@ -69,6 +69,7 @@ type source = {
   s_orig_name : string;                 (** Original guest name (if we rename
                                             the guest using -on, original is
                                             still saved here). *)
+  s_genid : string option;              (** VM Generation ID. *)
   s_memory : int64;                     (** Memory size (bytes). *)
   s_vcpu : int;                         (** Number of CPUs. *)
   s_cpu_vendor : string option;         (** Source CPU vendor. *)
--
2.17.1