mrc0mmand / rpms / libguestfs

Forked from rpms/libguestfs 3 years ago
Clone

Blame SOURCES/0003-v2v-ovf-Create-OVF-more-aligned-with-the-standard.patch

df3bb2
From d330b210b7d62ccd9f73909215251f4ce68cd6c9 Mon Sep 17 00:00:00 2001
df3bb2
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Golembiovsk=C3=BD?= <tgolembi@redhat.com>
df3bb2
Date: Thu, 22 Feb 2018 11:41:07 +0100
df3bb2
Subject: [PATCH] v2v: ovf: Create OVF more aligned with the standard
df3bb2
MIME-Version: 1.0
df3bb2
Content-Type: text/plain; charset=UTF-8
df3bb2
Content-Transfer-Encoding: 8bit
df3bb2
df3bb2
For historical reasons the OVF used in RHV export domain contains some
df3bb2
deviations from the OVF standard. The format used in -o rhv has to
df3bb2
remain fixed but for -o vdsm and we could produce much nicer OVF. This
df3bb2
patch serves as a preparatory step to this.
df3bb2
df3bb2
The main reason for creating different OVF is that it can be used to
df3bb2
create VM by oVirt REST API. The RHV export domain flavor cannot be used
df3bb2
that way.
df3bb2
df3bb2
For now the virt-v2v behavior is unchanged. The modified output will be
df3bb2
enabled in some later patch.
df3bb2
df3bb2
Signed-off-by: Tomáš Golembiovský <tgolembi@redhat.com>
df3bb2
(cherry picked from commit a52ed4b4454396eb13d2cdf5762292bff3104f66)
df3bb2
---
df3bb2
 v2v/create_ovf.ml  | 152 ++++++++++++++++++++++++++++++++-------------
df3bb2
 v2v/create_ovf.mli |  12 +++-
df3bb2
 v2v/output_rhv.ml  |   3 +-
df3bb2
 v2v/output_vdsm.ml |   3 +-
df3bb2
 4 files changed, 121 insertions(+), 49 deletions(-)
df3bb2
df3bb2
diff --git a/v2v/create_ovf.ml b/v2v/create_ovf.ml
df3bb2
index e9d569dc1..0ec0a088c 100644
df3bb2
--- a/v2v/create_ovf.ml
df3bb2
+++ b/v2v/create_ovf.ml
df3bb2
@@ -29,6 +29,10 @@ open Types
df3bb2
 open Utils
df3bb2
 open DOM
df3bb2
 
df3bb2
+type ovf_flavour =
df3bb2
+  | OVirt
df3bb2
+  | RHVExportStorageDomain
df3bb2
+
df3bb2
 (* We set the creation time to be the same for all dates in
df3bb2
  * all metadata files.  All dates in OVF are UTC.
df3bb2
  *)
df3bb2
@@ -295,7 +299,7 @@ let create_meta_files output_alloc sd_uuid image_uuids targets =
df3bb2
 
df3bb2
 (* Create the OVF file. *)
df3bb2
 let rec create_ovf source targets guestcaps inspect
df3bb2
-    output_alloc sd_uuid image_uuids vol_uuids vm_uuid =
df3bb2
+    output_alloc sd_uuid image_uuids vol_uuids vm_uuid ovf_flavour =
df3bb2
   assert (List.length targets = List.length vol_uuids);
df3bb2
 
df3bb2
   let memsize_mb = source.s_memory /^ 1024L /^ 1024L in
df3bb2
@@ -314,12 +318,26 @@ let rec create_ovf source targets guestcaps inspect
df3bb2
     ] [
df3bb2
       Comment generated_by;
df3bb2
       e "References" [] [];
df3bb2
-      e "Section" ["xsi:type", "ovf:NetworkSection_Type"] [
df3bb2
-        e "Info" [] [PCData "List of networks"]
df3bb2
-      ];
df3bb2
-      e "Section" ["xsi:type", "ovf:DiskSection_Type"] [
df3bb2
-        e "Info" [] [PCData "List of Virtual Disks"]
df3bb2
-      ];
df3bb2
+      (match ovf_flavour with
df3bb2
+      | OVirt ->
df3bb2
+        e "NetworkSection" [] [
df3bb2
+          e "Info" [] [PCData "List of networks"]
df3bb2
+        ]
df3bb2
+      | RHVExportStorageDomain ->
df3bb2
+        e "Section" ["xsi:type", "ovf:NetworkSection_Type"] [
df3bb2
+          e "Info" [] [PCData "List of networks"]
df3bb2
+        ]
df3bb2
+      );
df3bb2
+      (match ovf_flavour with
df3bb2
+      | OVirt ->
df3bb2
+        e "DiskSection" [] [
df3bb2
+          e "Info" [] [PCData "List of Virtual Disks"]
df3bb2
+        ]
df3bb2
+      | RHVExportStorageDomain ->
df3bb2
+        e "Section" ["xsi:type", "ovf:DiskSection_Type"] [
df3bb2
+          e "Info" [] [PCData "List of Virtual Disks"]
df3bb2
+        ]
df3bb2
+      );
df3bb2
 
df3bb2
       let content_subnodes = ref [
df3bb2
         e "Name" [] [PCData source.s_name];
df3bb2
@@ -352,11 +370,20 @@ let rec create_ovf source targets guestcaps inspect
df3bb2
       );
df3bb2
 
df3bb2
       List.push_back content_subnodes (
df3bb2
-        e "Section" ["ovf:id", vm_uuid; "ovf:required", "false";
df3bb2
-                     "xsi:type", "ovf:OperatingSystemSection_Type"] [
df3bb2
+        let osinfo_subnodes = [
df3bb2
           e "Info" [] [PCData inspect.i_product_name];
df3bb2
           e "Description" [] [PCData ostype];
df3bb2
-          ]
df3bb2
+        ] in
df3bb2
+        (match ovf_flavour with
df3bb2
+        | OVirt ->
df3bb2
+          e "OperatingSystemSection" ["ovf:id", vm_uuid;
df3bb2
+                                      "ovf:required", "false"]
df3bb2
+            osinfo_subnodes
df3bb2
+        | RHVExportStorageDomain ->
df3bb2
+          e "Section" ["ovf:id", vm_uuid; "ovf:required", "false";
df3bb2
+                       "xsi:type", "ovf:OperatingSystemSection_Type"]
df3bb2
+            osinfo_subnodes
df3bb2
+        )
df3bb2
       );
df3bb2
 
df3bb2
       let virtual_hardware_section_items = ref [
df3bb2
@@ -444,24 +471,34 @@ let rec create_ovf source targets guestcaps inspect
df3bb2
         );
df3bb2
 
df3bb2
       List.push_back content_subnodes (
df3bb2
-        e "Section" ["xsi:type", "ovf:VirtualHardwareSection_Type"]
df3bb2
-          !virtual_hardware_section_items
df3bb2
+        match ovf_flavour with
df3bb2
+        | OVirt ->
df3bb2
+          e "VirtualHardwareSection" [] !virtual_hardware_section_items
df3bb2
+        | RHVExportStorageDomain ->
df3bb2
+          e "Section" ["xsi:type", "ovf:VirtualHardwareSection_Type"]
df3bb2
+            !virtual_hardware_section_items
df3bb2
       );
df3bb2
 
df3bb2
-      e "Content" ["ovf:id", "out"; "xsi:type", "ovf:VirtualSystem_Type"]
df3bb2
-        !content_subnodes
df3bb2
+      (match ovf_flavour with
df3bb2
+      | OVirt ->
df3bb2
+        e "VirtualSystem" ["ovf:id", "out"] !content_subnodes
df3bb2
+      | RHVExportStorageDomain ->
df3bb2
+        e "Content" ["ovf:id", "out"; "xsi:type", "ovf:VirtualSystem_Type"]
df3bb2
+          !content_subnodes
df3bb2
+      )
df3bb2
     ] in
df3bb2
 
df3bb2
   (* Add disks to the OVF XML. *)
df3bb2
-  add_disks targets guestcaps output_alloc sd_uuid image_uuids vol_uuids ovf;
df3bb2
+  add_disks targets guestcaps output_alloc sd_uuid image_uuids vol_uuids
df3bb2
+    ovf_flavour ovf;
df3bb2
 
df3bb2
   (* Old virt-v2v ignored removable media. XXX *)
df3bb2
 
df3bb2
   (* Add networks to the OVF XML. *)
df3bb2
-  add_networks source.s_nics guestcaps ovf;
df3bb2
+  add_networks source.s_nics guestcaps ovf_flavour ovf;
df3bb2
 
df3bb2
   (* Add sound card to the OVF XML. *)
df3bb2
-  add_sound_card source.s_sound ovf;
df3bb2
+  add_sound_card source.s_sound ovf_flavour ovf;
df3bb2
 
df3bb2
   (* Old virt-v2v didn't really look at the video and display
df3bb2
    * metadata, instead just adding a single standard display (see
df3bb2
@@ -481,21 +518,42 @@ let rec create_ovf source targets guestcaps inspect
df3bb2
   (* Return the OVF document. *)
df3bb2
   ovf
df3bb2
 
df3bb2
+(* Find appropriate section depending on the OVF flavour being generated.
df3bb2
+ *
df3bb2
+ * For example normal disk section is in node <DiskSection> whereas in case of
df3bb2
+ * RHV export storage domain it is <Section xsi:type="ovf:DiskSection_Type">.
df3bb2
+ *)
df3bb2
+and get_flavoured_section ovf ovf_flavour ovirt_path rhv_path rhv_path_attr =
df3bb2
+  let nodes =
df3bb2
+    match ovf_flavour with
df3bb2
+    | OVirt ->
df3bb2
+      let nodes = path_to_nodes ovf ovirt_path in
df3bb2
+      (match nodes with
df3bb2
+      | [node] -> node
df3bb2
+      | [] | _::_::_ -> assert false)
df3bb2
+    | RHVExportStorageDomain ->
df3bb2
+      let nodes = path_to_nodes ovf rhv_path in
df3bb2
+      try find_node_by_attr nodes rhv_path_attr
df3bb2
+      with Not_found -> assert false
df3bb2
+  in
df3bb2
+  nodes
df3bb2
+
df3bb2
 (* This modifies the OVF DOM, adding a section for each disk. *)
df3bb2
-and add_disks targets guestcaps output_alloc sd_uuid image_uuids vol_uuids ovf =
df3bb2
+and add_disks targets guestcaps output_alloc sd_uuid image_uuids vol_uuids
df3bb2
+    ovf_flavour ovf =
df3bb2
   let references =
df3bb2
     let nodes = path_to_nodes ovf ["ovf:Envelope"; "References"] in
df3bb2
     match nodes with
df3bb2
     | [] | _::_::_ -> assert false
df3bb2
     | [node] -> node in
df3bb2
-  let disk_section =
df3bb2
-    let sections = path_to_nodes ovf ["ovf:Envelope"; "Section"] in
df3bb2
-    try find_node_by_attr sections ("xsi:type", "ovf:DiskSection_Type")
df3bb2
-    with Not_found -> assert false in
df3bb2
-  let virtualhardware_section =
df3bb2
-    let sections = path_to_nodes ovf ["ovf:Envelope"; "Content"; "Section"] in
df3bb2
-    try find_node_by_attr sections ("xsi:type", "ovf:VirtualHardwareSection_Type")
df3bb2
-    with Not_found -> assert false in
df3bb2
+  let disk_section = get_flavoured_section ovf ovf_flavour
df3bb2
+    ["ovf:Envelope"; "DiskSection"]
df3bb2
+    ["ovf:Envelope"; "Section"]
df3bb2
+    ("xsi:type", "ovf:DiskSection_Type") in
df3bb2
+  let virtualhardware_section = get_flavoured_section ovf ovf_flavour
df3bb2
+    ["ovf:Envelope"; "VirtualSystem"; "VirtualHardwareSection"]
df3bb2
+    ["ovf:Envelope"; "Content"; "Section"]
df3bb2
+    ("xsi:type", "ovf:VirtualHardwareSection_Type") in
df3bb2
 
df3bb2
   (* Iterate over the disks, adding them to the OVF document. *)
df3bb2
   List.iteri (
df3bb2
@@ -509,7 +567,12 @@ and add_disks targets guestcaps output_alloc sd_uuid image_uuids vol_uuids ovf =
df3bb2
       let is_bootable_drive = i == 0 in
df3bb2
       let boot_order = i+1 in
df3bb2
 
df3bb2
-      let fileref = sprintf "%s/%s" image_uuid vol_uuid in
df3bb2
+      let fileref =
df3bb2
+        match ovf_flavour with
df3bb2
+        | OVirt ->
df3bb2
+          vol_uuid
df3bb2
+        | RHVExportStorageDomain ->
df3bb2
+          sprintf "%s/%s" image_uuid vol_uuid in
df3bb2
 
df3bb2
       (* ovf:size and ovf:actual_size fields are integer GBs.  If you
df3bb2
        * use floating point numbers then RHV will fail to parse them.
df3bb2
@@ -560,7 +623,10 @@ and add_disks targets guestcaps output_alloc sd_uuid image_uuids vol_uuids ovf =
df3bb2
       (* Add disk to DiskSection. *)
df3bb2
       let disk =
df3bb2
         let attrs = ref [
df3bb2
-          "ovf:diskId", vol_uuid;
df3bb2
+          "ovf:diskId",
df3bb2
+          (match ovf_flavour with
df3bb2
+          | OVirt -> image_uuid
df3bb2
+          | RHVExportStorageDomain -> vol_uuid);
df3bb2
           "ovf:size", Int64.to_string size_gb;
df3bb2
           "ovf:capacity", Int64.to_string ov.ov_virtual_size;
df3bb2
           "ovf:fileRef", fileref;
df3bb2
@@ -619,15 +685,15 @@ and add_disks targets guestcaps output_alloc sd_uuid image_uuids vol_uuids ovf =
df3bb2
   ) (List.combine3 targets image_uuids vol_uuids)
df3bb2
 
df3bb2
 (* This modifies the OVF DOM, adding a section for each NIC. *)
df3bb2
-and add_networks nics guestcaps ovf =
df3bb2
-  let network_section =
df3bb2
-    let sections = path_to_nodes ovf ["ovf:Envelope"; "Section"] in
df3bb2
-    try find_node_by_attr sections ("xsi:type", "ovf:NetworkSection_Type")
df3bb2
-    with Not_found -> assert false in
df3bb2
-  let virtualhardware_section =
df3bb2
-    let sections = path_to_nodes ovf ["ovf:Envelope"; "Content"; "Section"] in
df3bb2
-    try find_node_by_attr sections ("xsi:type", "ovf:VirtualHardwareSection_Type")
df3bb2
-    with Not_found -> assert false in
df3bb2
+and add_networks nics guestcaps ovf_flavour ovf =
df3bb2
+  let network_section = get_flavoured_section ovf ovf_flavour
df3bb2
+    ["ovf:Envelope"; "NetworkSection"]
df3bb2
+    ["ovf:Envelope"; "Section"]
df3bb2
+    ("xsi:type", "ovf:NetworkSection_Type") in
df3bb2
+  let virtualhardware_section = get_flavoured_section ovf ovf_flavour
df3bb2
+    ["ovf:Envelope"; "VirtualSystem"; "VirtualHardwareSection"]
df3bb2
+    ["ovf:Envelope"; "Content"; "Section"]
df3bb2
+    ("xsi:type", "ovf:VirtualHardwareSection_Type") in
df3bb2
 
df3bb2
   (* Iterate over the NICs, adding them to the OVF document. *)
df3bb2
   List.iteri (
df3bb2
@@ -675,7 +741,7 @@ and add_networks nics guestcaps ovf =
df3bb2
   ) nics
df3bb2
 
df3bb2
 (* This modifies the OVF DOM, adding a sound card, if oVirt can emulate it. *)
df3bb2
-and add_sound_card sound ovf =
df3bb2
+and add_sound_card sound ovf_flavour ovf =
df3bb2
   let device =
df3bb2
     match sound with
df3bb2
     | None -> None
df3bb2
@@ -688,12 +754,10 @@ and add_sound_card sound ovf =
df3bb2
 
df3bb2
   match device with
df3bb2
   | Some device ->
df3bb2
-     let virtualhardware_section =
df3bb2
-       let sections =
df3bb2
-         path_to_nodes ovf ["ovf:Envelope"; "Content"; "Section"] in
df3bb2
-       try find_node_by_attr sections
df3bb2
-                             ("xsi:type", "ovf:VirtualHardwareSection_Type")
df3bb2
-       with Not_found -> assert false in
df3bb2
+     let virtualhardware_section = get_flavoured_section ovf ovf_flavour
df3bb2
+       ["ovf:Envelope"; "VirtualSystem"; "VirtualHardwareSection"]
df3bb2
+       ["ovf:Envelope"; "Content"; "Section"]
df3bb2
+       ("xsi:type", "ovf:VirtualHardwareSection_Type") in
df3bb2
 
df3bb2
      let item =
df3bb2
        e "Item" [] [
df3bb2
diff --git a/v2v/create_ovf.mli b/v2v/create_ovf.mli
df3bb2
index 07e8af6a0..8a8c7dd12 100644
df3bb2
--- a/v2v/create_ovf.mli
df3bb2
+++ b/v2v/create_ovf.mli
df3bb2
@@ -16,16 +16,22 @@
df3bb2
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
df3bb2
  *)
df3bb2
 
df3bb2
+type ovf_flavour =
df3bb2
+  | OVirt
df3bb2
+  | RHVExportStorageDomain
df3bb2
+
df3bb2
 (** Create OVF and related files for RHV.
df3bb2
 
df3bb2
-    The format is described in
df3bb2
-    http://www.ovirt.org/images/8/86/Ovirt_ovf_format.odt
df3bb2
+    The format for RHV export storage domain is described in:
df3bb2
+    http://resources.ovirt.org/old-site-files/Ovirt_ovf_format.odt
df3bb2
+
df3bb2
+    The format understood by oVirt has no known documentation.
df3bb2
 
df3bb2
     OVF isn't a real standard, so it's likely that if we ever had to
df3bb2
     create OVF for another target management system then we would need
df3bb2
     to heavily modify or even duplicate this code. *)
df3bb2
 
df3bb2
-val create_ovf : Types.source -> Types.target list -> Types.guestcaps -> Types.inspect -> Types.output_allocation -> string -> string list -> string list -> string -> DOM.doc
df3bb2
+val create_ovf : Types.source -> Types.target list -> Types.guestcaps -> Types.inspect -> Types.output_allocation -> string -> string list -> string list -> string ->  ovf_flavour -> DOM.doc
df3bb2
 (** Create the OVF file.
df3bb2
 
df3bb2
     Actually a {!DOM} document is created, not a file.  It can be written
df3bb2
diff --git a/v2v/output_rhv.ml b/v2v/output_rhv.ml
df3bb2
index 0b732e4cf..5260ab030 100644
df3bb2
--- a/v2v/output_rhv.ml
df3bb2
+++ b/v2v/output_rhv.ml
df3bb2
@@ -275,7 +275,8 @@ object
df3bb2
 
df3bb2
     (* Create the metadata. *)
df3bb2
     let ovf = Create_ovf.create_ovf source targets guestcaps inspect
df3bb2
-      output_alloc esd_uuid image_uuids vol_uuids vm_uuid in
df3bb2
+      output_alloc esd_uuid image_uuids vol_uuids vm_uuid
df3bb2
+      Create_ovf.RHVExportStorageDomain in
df3bb2
 
df3bb2
     (* Write it to the metadata file. *)
df3bb2
     let dir = esd_mp // esd_uuid // "master" // "vms" // vm_uuid in
df3bb2
diff --git a/v2v/output_vdsm.ml b/v2v/output_vdsm.ml
df3bb2
index c5e904ba1..ce286d327 100644
df3bb2
--- a/v2v/output_vdsm.ml
df3bb2
+++ b/v2v/output_vdsm.ml
df3bb2
@@ -175,7 +175,8 @@ object
df3bb2
       output_alloc dd_uuid
df3bb2
       vdsm_options.image_uuids
df3bb2
       vdsm_options.vol_uuids
df3bb2
-      vdsm_options.vm_uuid in
df3bb2
+      vdsm_options.vm_uuid
df3bb2
+      Create_ovf.RHVExportStorageDomain in
df3bb2
 
df3bb2
     (* Write it to the metadata file. *)
df3bb2
     let file = vdsm_options.ovf_output // vdsm_options.vm_uuid ^ ".ovf" in
df3bb2
-- 
df3bb2
2.21.0
df3bb2