From 479f2cc10e74304e2d6202ad13dd99bdc9a6923d Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Thu, 5 Dec 2024 13:26:43 +0000 Subject: [PATCH] inspector: Move the code that creates XML output to a separate file Simple code motion, so that we can reuse this code in virt-v2v-in-place. (cherry picked from commit 3d2d65a04ae75716c084063b572ff916fa83fd1b) --- inspector/Makefile.am | 2 + inspector/create_inspector_xml.ml | 167 +++++++++++++++++++++++++++++ inspector/create_inspector_xml.mli | 22 ++++ inspector/inspector.ml | 144 +------------------------ 4 files changed, 193 insertions(+), 142 deletions(-) create mode 100644 inspector/create_inspector_xml.ml create mode 100644 inspector/create_inspector_xml.mli diff --git a/inspector/Makefile.am b/inspector/Makefile.am index 172b2dc0..15f8cc34 100644 --- a/inspector/Makefile.am +++ b/inspector/Makefile.am @@ -23,9 +23,11 @@ EXTRA_DIST = \ $(SOURCES_C) SOURCES_MLI = \ + create_inspector_xml.mli \ inspector.mli SOURCES_ML = \ + create_inspector_xml.ml \ inspector.ml SOURCES_C = \ diff --git a/inspector/create_inspector_xml.ml b/inspector/create_inspector_xml.ml new file mode 100644 index 00000000..a3281d46 --- /dev/null +++ b/inspector/create_inspector_xml.ml @@ -0,0 +1,167 @@ +(* virt-v2v-inspector + * Copyright (C) 2009-2022 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + *) + +open Printf + +open Std_utils +open Tools_utils + +open Types +open Utils +open DOM + +(* This is where we construct the final XML document based on + * these inputs: + * - Global configuration like the version of v2v etc. + * - The NBD input sockets: v2vdir // "in0", "in1", etc + * - The inspection data (Types.inspect) + *) +let rec create_inspector_xml v2vdir inspect target_meta = + let body = ref [] in + + (* Record the version of virt-v2v etc, mainly for debugging. *) + List.push_back_list body [ + Comment generated_by; + e "program" [] [PCData "virt-v2v-inspector"]; + e "package" [] [PCData Config.package_name]; + e "version" [] [PCData Config.package_version]; + ]; + + (* The disks. *) + let disks = ref [] in + + List.iter ( + fun (i, virtual_size) -> + let elems = ref [] in + List.push_back elems (e "virtual-size" [] + [PCData (Int64.to_string virtual_size)]); + (match get_input_disk_allocated v2vdir i with + | None -> () + | Some real_size -> + List.push_back elems (e "allocated" [ "estimated", "true" ] + [PCData (Int64.to_string real_size)]) + ); + + List.push_back disks (e "disk" [ "index", string_of_int i ] !elems) + ) (get_disks v2vdir); + List.push_back body (e "disks" [] !disks); + + (* The field is outside the element, + * since firmware is not part of the OS, and also because this is + * consistent with virt-drivers output. + *) + List.push_back body + (e "firmware" + ["type", + string_of_target_firmware target_meta.target_firmware] + []); + + (* The inspection data. *) + (* NB: Keep these field names compatible with virt-inspector! *) + let os = ref [] in + List.push_back os (e "name" [] [PCData inspect.i_type]); + List.push_back os (e "distro" [] [PCData inspect.i_distro]); + List.push_back os (e "osinfo" [] [PCData inspect.i_osinfo]); + List.push_back os (e "arch" [] [PCData inspect.i_arch]); + List.push_back os (e "major_version" [] + [PCData (string_of_int inspect.i_major_version)]); + List.push_back os (e "minor_version" [] + [PCData (string_of_int inspect.i_minor_version)]); + if inspect.i_package_format <> "" then + List.push_back os (e "package_format" [] + [PCData inspect.i_package_format]); + if inspect.i_package_management <> "" then + List.push_back os (e "package_management" [] + [PCData inspect.i_package_management]); + if inspect.i_product_name <> "" then + List.push_back os (e "product_name" [] [PCData inspect.i_product_name]); + if inspect.i_product_variant <> "" then + List.push_back os (e "product_variant" [] + [PCData inspect.i_product_variant]); + + if inspect.i_windows_systemroot <> "" then + List.push_back os (e "windows_systemroot" [] + [PCData inspect.i_windows_systemroot]); + if inspect.i_windows_software_hive <> "" then + List.push_back os (e "windows_software_hive" [] + [PCData inspect.i_windows_software_hive]); + if inspect.i_windows_systemroot <> "" then + List.push_back os (e "windows_system_hive" [] + [PCData inspect.i_windows_system_hive]); + if inspect.i_windows_current_control_set <> "" then + List.push_back os (e "windows_current_control_set" [] + [PCData inspect.i_windows_current_control_set]); + + List.push_back os (e "root" [] [PCData inspect.i_root]); + let mps = ref [] in + List.iter ( + fun (fs, dev) -> + List.push_back mps (e "mountpoint" [ "dev", dev ] [PCData fs]) + ) inspect.i_mountpoints; + List.push_back os (e "mountpoints" [] !mps); + + List.push_back body (e "operatingsystem" [] !os); + + (* Construct the final document. *) + (doc "v2v-inspection" [] !body : DOM.doc) + + +(* This is a copy of {!Output.get_disks}. *) +and get_disks dir = + let rec loop acc i = + let socket = sprintf "%s/in%d" dir i in + if Sys.file_exists socket then ( + let size = Utils.with_nbd_connect_unix ~socket NBD.get_size in + loop ((i, size) :: acc) (i+1) + ) + else + List.rev acc + in + loop [] 0 + +(* This is like {!Utils.get_disk_allocated} but works on the input disks. *) +and get_input_disk_allocated dir i = + let socket = sprintf "%s/in%d" dir i + and alloc_ctx = "base:allocation" in + with_nbd_connect_unix ~socket ~meta_contexts:[alloc_ctx] + (fun nbd -> + if NBD.can_meta_context nbd alloc_ctx then ( + (* Get the list of extents, using a 2GiB chunk size as hint. *) + let size = NBD.get_size nbd + and allocated = ref 0_L + and fetch_offset = ref 0_L in + while !fetch_offset < size do + let remaining = size -^ !fetch_offset in + let fetch_size = min 0x8000_0000_L remaining in + NBD.block_status nbd fetch_size !fetch_offset + (fun ctx offset entries err -> + assert (ctx = alloc_ctx); + for i = 0 to Array.length entries / 2 - 1 do + let len = entries.(i * 2) + and typ = entries.(i * 2 + 1) in + assert (len > 0_L); + if typ &^ 1_L = 0_L then + allocated := !allocated +^ len; + fetch_offset := !fetch_offset +^ len + done; + 0 + ) + done; + Some !allocated + ) else None + ) diff --git a/inspector/create_inspector_xml.mli b/inspector/create_inspector_xml.mli new file mode 100644 index 00000000..4f09269c --- /dev/null +++ b/inspector/create_inspector_xml.mli @@ -0,0 +1,22 @@ +(* virt-v2v-in-place + * Copyright (C) 2009-2024 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + *) + +val create_inspector_xml : string -> Types.inspect -> Types.target_meta -> + DOM.doc +(** Create the XML output of virt-v2v-inspector which contains the + post-conversion metadata. *) diff --git a/inspector/inspector.ml b/inspector/inspector.ml index aeddbec6..ac26146f 100644 --- a/inspector/inspector.ml +++ b/inspector/inspector.ml @@ -27,7 +27,7 @@ open Getopt.OptionName open Types open Utils -open DOM +open Create_inspector_xml (* Matches --mac command line parameters. *) let mac_re = PCRE.compile "^([[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}):(network|bridge|ip):(.*)$" @@ -368,7 +368,7 @@ read the man page virt-v2v-inspector(1). ); (* Dump out the information. *) - let doc = inspector_xml v2vdir inspect target_meta in + let doc = create_inspector_xml v2vdir inspect target_meta in let chan = match output_file with | None -> Stdlib.stdout @@ -404,144 +404,4 @@ and check_host_free_space () = \"Minimum free space check in the host\".") large_tmpdir (human_size free_space) -(* This is a copy of {!Output.get_disks}. *) -and get_disks dir = - let rec loop acc i = - let socket = sprintf "%s/in%d" dir i in - if Sys.file_exists socket then ( - let size = Utils.with_nbd_connect_unix ~socket NBD.get_size in - loop ((i, size) :: acc) (i+1) - ) - else - List.rev acc - in - loop [] 0 - -(* This is like {!Utils.get_disk_allocated} but works on the input disks. *) -and get_input_disk_allocated dir i = - let socket = sprintf "%s/in%d" dir i - and alloc_ctx = "base:allocation" in - with_nbd_connect_unix ~socket ~meta_contexts:[alloc_ctx] - (fun nbd -> - if NBD.can_meta_context nbd alloc_ctx then ( - (* Get the list of extents, using a 2GiB chunk size as hint. *) - let size = NBD.get_size nbd - and allocated = ref 0_L - and fetch_offset = ref 0_L in - while !fetch_offset < size do - let remaining = size -^ !fetch_offset in - let fetch_size = min 0x8000_0000_L remaining in - NBD.block_status nbd fetch_size !fetch_offset - (fun ctx offset entries err -> - assert (ctx = alloc_ctx); - for i = 0 to Array.length entries / 2 - 1 do - let len = entries.(i * 2) - and typ = entries.(i * 2 + 1) in - assert (len > 0_L); - if typ &^ 1_L = 0_L then - allocated := !allocated +^ len; - fetch_offset := !fetch_offset +^ len - done; - 0 - ) - done; - Some !allocated - ) else None - ) - -(* This is where we construct the final XML document based on - * these inputs: - * - Global configuration like the version of v2v etc. - * - The NBD input sockets: v2vdir // "in0", "in1", etc - * - The inspection data (Types.inspect) - *) -and inspector_xml v2vdir inspect target_meta = - let body = ref [] in - - (* Record the version of virt-v2v etc, mainly for debugging. *) - List.push_back_list body [ - Comment generated_by; - e "program" [] [PCData "virt-v2v-inspector"]; - e "package" [] [PCData Config.package_name]; - e "version" [] [PCData Config.package_version]; - ]; - - (* The disks. *) - let disks = ref [] in - - List.iter ( - fun (i, virtual_size) -> - let elems = ref [] in - List.push_back elems (e "virtual-size" [] - [PCData (Int64.to_string virtual_size)]); - (match get_input_disk_allocated v2vdir i with - | None -> () - | Some real_size -> - List.push_back elems (e "allocated" [ "estimated", "true" ] - [PCData (Int64.to_string real_size)]) - ); - - List.push_back disks (e "disk" [ "index", string_of_int i ] !elems) - ) (get_disks v2vdir); - List.push_back body (e "disks" [] !disks); - - (* The field is outside the element, - * since firmware is not part of the OS, and also because this is - * consistent with virt-drivers output. - *) - List.push_back body - (e "firmware" - ["type", - string_of_target_firmware target_meta.target_firmware] - []); - - (* The inspection data. *) - (* NB: Keep these field names compatible with virt-inspector! *) - let os = ref [] in - List.push_back os (e "name" [] [PCData inspect.i_type]); - List.push_back os (e "distro" [] [PCData inspect.i_distro]); - List.push_back os (e "osinfo" [] [PCData inspect.i_osinfo]); - List.push_back os (e "arch" [] [PCData inspect.i_arch]); - List.push_back os (e "major_version" [] - [PCData (string_of_int inspect.i_major_version)]); - List.push_back os (e "minor_version" [] - [PCData (string_of_int inspect.i_minor_version)]); - if inspect.i_package_format <> "" then - List.push_back os (e "package_format" [] - [PCData inspect.i_package_format]); - if inspect.i_package_management <> "" then - List.push_back os (e "package_management" [] - [PCData inspect.i_package_management]); - if inspect.i_product_name <> "" then - List.push_back os (e "product_name" [] [PCData inspect.i_product_name]); - if inspect.i_product_variant <> "" then - List.push_back os (e "product_variant" [] - [PCData inspect.i_product_variant]); - - if inspect.i_windows_systemroot <> "" then - List.push_back os (e "windows_systemroot" [] - [PCData inspect.i_windows_systemroot]); - if inspect.i_windows_software_hive <> "" then - List.push_back os (e "windows_software_hive" [] - [PCData inspect.i_windows_software_hive]); - if inspect.i_windows_systemroot <> "" then - List.push_back os (e "windows_system_hive" [] - [PCData inspect.i_windows_system_hive]); - if inspect.i_windows_current_control_set <> "" then - List.push_back os (e "windows_current_control_set" [] - [PCData inspect.i_windows_current_control_set]); - - List.push_back os (e "root" [] [PCData inspect.i_root]); - let mps = ref [] in - List.iter ( - fun (fs, dev) -> - List.push_back mps (e "mountpoint" [ "dev", dev ] [PCData fs]) - ) inspect.i_mountpoints; - List.push_back os (e "mountpoints" [] !mps); - - List.push_back body (e "operatingsystem" [] !os); - - (* Construct the final document. *) - (doc "v2v-inspection" [] !body : DOM.doc) - let () = run_main_and_handle_errors main