[Libguestfs] [PATCH 3/3] v2v: add -o json output mode

Richard W.M. Jones rjones at redhat.com
Mon Mar 25 15:00:54 UTC 2019


If we pushed the baseline of OCaml up by (I think) just a single
version then most of this code could be generated automatically from
the description in the Types module.  It would rely on the "new"
(actually rather old) feature called extension points (ppx) which I
think was added in 4.02.

However in its own terms the idea behind this patch is fine.  As I
said in the previous email I'm somewhat unhappy with a homebrew
templating system - could you check if there's anything out there that
we could easily use already?  If not then I guess we'd need to go with
homebrew.

Rich.

> +  !doc
> diff --git a/v2v/create_json.mli b/v2v/create_json.mli
> new file mode 100644
> index 000000000..6dbb6e48b
> --- /dev/null
> +++ b/v2v/create_json.mli
> @@ -0,0 +1,29 @@
> +(* virt-v2v
> + * Copyright (C) 2019 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.
> + *)
> +
> +(** Create JSON metadata for [-o json]. *)
> +
> +val create_json_metadata : Types.source -> Types.target list ->
> +                           Types.target_buses ->
> +                           Types.guestcaps ->
> +                           Types.inspect ->
> +                           Types.target_firmware ->
> +                           JSON.doc
> +(** [create_json_metadata source targets target_buses guestcaps
> +    inspect target_firmware] creates the JSON with the majority
> +    of the data that virt-v2v used for the conversion. *)
> diff --git a/v2v/output_json.ml b/v2v/output_json.ml
> new file mode 100644
> index 000000000..ca0bda978
> --- /dev/null
> +++ b/v2v/output_json.ml
> @@ -0,0 +1,116 @@
> +(* virt-v2v
> + * Copyright (C) 2019 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 Common_gettext.Gettext
> +
> +open Types
> +open Utils
> +
> +type json_options = {
> +  json_disks_pattern : string;
> +}
> +
> +let print_output_options () =
> +  printf (f_"Output options (-oo) which can be used with -o json:
> +
> +  -oo json-disks-pattern=PATTERN   Pattern for the disks.
> +")
> +
> +let known_pattern_variables = ["DiskNo"; "DiskDeviceName"; "GuestName"]
> +
> +let parse_output_options options =
> +  let json_disks_pattern = ref None in
> +
> +  List.iter (
> +    function
> +    | "json-disks-pattern", v ->
> +       if !json_disks_pattern <> None then
> +         error (f_"-o json: -oo json-disks-pattern set more than once");
> +       let vars =
> +         try Var_expander.scan_variables v
> +         with Var_expander.Invalid_variable var ->
> +           error (f_"-o json: -oo json-disks-pattern: invalid variable %%{%s}")
> +             var in
> +       List.iter (
> +         fun var ->
> +           if not (List.mem var known_pattern_variables) then
> +             error (f_"-o json: -oo json-disks-pattern: unhandled variable %%{%s}")
> +               var
> +       ) vars;
> +       json_disks_pattern := Some v
> +    | k, _ ->
> +       error (f_"-o json: unknown output option ‘-oo %s’") k
> +  ) options;
> +
> +  let json_disks_pattern =
> +    Option.default "%{GuestName}-%{DiskDeviceName}" !json_disks_pattern in
> +
> +  { json_disks_pattern }
> +
> +class output_json dir json_options = object
> +  inherit output
> +
> +  method as_options = sprintf "-o json -os %s" dir
> +
> +  method prepare_targets source overlays _ _ _ _ =
> +    List.mapi (
> +      fun i (_, ov) ->
> +        let outname =
> +          let vars_fn = function
> +            | "DiskNo" -> Some (string_of_int (i+1))
> +            | "DiskDeviceName" -> Some ov.ov_sd
> +            | "GuestName" -> Some source.s_name
> +            | _ -> assert false
> +          in
> +          Var_expander.replace_fn json_options.json_disks_pattern vars_fn in
> +        let destname = dir // outname in
> +        mkdir_p (Filename.dirname destname) 0o755;
> +        TargetFile destname
> +    ) overlays
> +
> +  method supported_firmware = [ TargetBIOS; TargetUEFI ]
> +
> +  method create_metadata source targets
> +                         target_buses guestcaps inspect target_firmware =
> +    let doc =
> +      Create_json.create_json_metadata source targets target_buses
> +                                       guestcaps inspect target_firmware in
> +    let doc_string = JSON.string_of_doc ~fmt:JSON.Indented doc in
> +
> +    if verbose () then (
> +      eprintf "resulting JSON:\n";
> +      output_string stderr doc_string;
> +      eprintf "\n\n%!";
> +    );
> +
> +    let name = source.s_name in
> +    let file = dir // name ^ ".json" in
> +
> +    with_open_out file (
> +      fun chan ->
> +        output_string chan doc_string;
> +        output_char chan '\n'
> +    )
> +end
> +
> +let output_json = new output_json
> +let () = Modules_list.register_output_module "json"
> diff --git a/v2v/output_json.mli b/v2v/output_json.mli
> new file mode 100644
> index 000000000..52f58f2d1
> --- /dev/null
> +++ b/v2v/output_json.mli
> @@ -0,0 +1,31 @@
> +(* virt-v2v
> + * Copyright (C) 2019 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.
> + *)
> +
> +(** [-o json] target. *)
> +
> +type json_options
> +(** Miscellaneous extra command line parameters used by json. *)
> +
> +val print_output_options : unit -> unit
> +val parse_output_options : (string * string) list -> json_options
> +(** Print and parse json -oo options. *)
> +
> +val output_json : string -> json_options -> Types.output
> +(** [output_json directory json_options] creates and returns a new
> +    {!Types.output} object specialized for writing output to local
> +    files with JSON metadata. *)
> diff --git a/v2v/virt-v2v-output-local.pod b/v2v/virt-v2v-output-local.pod
> index 7427b1ed7..ec737e1ba 100644
> --- a/v2v/virt-v2v-output-local.pod
> +++ b/v2v/virt-v2v-output-local.pod
> @@ -11,6 +11,9 @@ or libvirt
>  
>   virt-v2v [-i* options] -o qemu -os DIRECTORY [--qemu-boot]
>  
> + virt-v2v [-i* options] -o json -os DIRECTORY
> +                        [-oo json-disks-pattern=PATTERN]
> +
>   virt-v2v [-i* options] -o null
>  
>  =head1 DESCRIPTION
> @@ -54,6 +57,13 @@ above, a shell script is created which contains the raw qemu command
>  you would need to boot the guest.  However the shell script is not
>  run, I<unless> you also add the I<--qemu-boot> option.
>  
> +=item B<-o json -os> C<DIRECTORY>
> +
> +This converts the guest to files in C<DIRECTORY>.  The metadata
> +produced is a JSON file containing the majority of the data virt-v2v
> +gathers during the conversion.
> +See L</OUTPUT TO JSON> below.
> +
>  =item B<-o null>
>  
>  The guest is converted, but the final result is thrown away and no
> @@ -140,6 +150,46 @@ Define the final guest in libvirt:
>  
>  =back
>  
> +=head1 OUTPUT TO JSON
> +
> +The I<-o json> option produces the following files by default:
> +
> + NAME.json                     JSON metadata.
> + NAME-sda, NAME-sdb, etc.      Guest disk(s).
> +
> +where C<NAME> is the guest name.
> +
> +It is possible to change the pattern of the disks using the
> +I<-oo json-disks-pattern=...> option: it allows parameters in form of
> +C<%{...}> variables, for example:
> +
> + -oo json-disks-pattern=disk%{DiskNo}.img
> +
> +Recognized variables are:
> +
> +=over 4
> +
> +=item C<%{DiskNo}>
> +
> +The index of the disk, starting from 1.
> +
> +=item C<%{DiskDeviceName}>
> +
> +The destination device of the disk, e.g. C<sda>, C<sdb>, etc.
> +
> +=item C<%{GuestName}>
> +
> +The name of the guest.
> +
> +=back
> +
> +Using a pattern it is possible use subdirectories for the disks,
> +even with names depending on variables; for example:
> +
> + -oo json-disks-pattern=%{GuestName}-%{DiskNo}/disk.img
> +
> +The default pattern is C<%{GuestName}-%{DiskDeviceName}>.
> +
>  =head1 SEE ALSO
>  
>  L<virt-v2v(1)>.
> diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
> index cf9464834..9a555c3be 100644
> --- a/v2v/virt-v2v.pod
> +++ b/v2v/virt-v2v.pod
> @@ -425,6 +425,17 @@ instead.
>  Set the output method to OpenStack Glance.  In this mode the converted
>  guest is uploaded to Glance.  See L<virt-v2v-output-openstack(1)>.
>  
> +=item B<-o> B<json>
> +
> +Set the output method to I<json>.
> +
> +In this mode, the converted guest is written to a local directory
> +specified by I<-os /dir> (the directory must exist), with a JSON file
> +containing the majority of the metadata that virt-v2v gathered during
> +the conversion.
> +
> +See L<virt-v2v-output-local(1)>.
> +
>  =item B<-o> B<libvirt>
>  
>  Set the output method to I<libvirt>.  This is the default.
> @@ -696,8 +707,8 @@ The location of the storage for the converted guest.
>  For I<-o libvirt>, this is a libvirt directory pool
>  (see S<C<virsh pool-list>>) or pool UUID.
>  
> -For I<-o local> and I<-o qemu>, this is a directory name.  The
> -directory must exist.
> +For I<-o json>, I<-o local> and I<-o qemu>, this is a directory name.
> +The directory must exist.
>  
>  For I<-o rhv-upload>, this is the name of the destination Storage
>  Domain.
> -- 
> 2.20.1
> 
> _______________________________________________
> Libguestfs mailing list
> Libguestfs at redhat.com
> https://www.redhat.com/mailman/listinfo/libguestfs

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
Fedora Windows cross-compiler. Compile Windows programs, test, and
build Windows installers. Over 100 libraries supported.
http://fedoraproject.org/wiki/MinGW




More information about the Libguestfs mailing list