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