mrc0mmand / rpms / libguestfs

Forked from rpms/libguestfs 3 years ago
Clone

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

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