These are a prelude to fixing https://bugzilla.redhat.com/show_bug.cgi?id=1590220 A lot of the virt-p2v configuration code was duplicated manually. These changes make sure that most of it is generated. Rich.
Richard W.M. Jones
2018-Jun-29 12:16 UTC
[Libguestfs] [PATCH 1/3] p2v: Generate config struct and p2v/config.c.
Mostly refactoring to make it easier to add fields to this struct in future. I'd like to call the header p2v/config.h but that's not possible since it conflicts with the autoconf-generated file. --- .gitignore | 2 + generator/Makefile.am | 3 + generator/main.ml | 5 + generator/p2v_config.ml | 389 +++++++++++++++++++++++++++++++++++ generator/p2v_config.mli | 20 ++ p2v/Makefile.am | 5 +- p2v/config.c | 208 ------------------- p2v/p2v.h | 56 +---- p2v/test-virt-p2v-cmdline.sh | 14 +- 9 files changed, 431 insertions(+), 271 deletions(-) diff --git a/.gitignore b/.gitignore index d25089677..4c0ff4e1e 100644 --- a/.gitignore +++ b/.gitignore @@ -430,10 +430,12 @@ Makefile.in /ocaml/t/*.bc /ocaml/t/*.opt /p2v/about-authors.c +/p2v/config.c /p2v/dependencies.archlinux /p2v/dependencies.debian /p2v/dependencies.redhat /p2v/dependencies.suse +/p2v/p2v-config.h /p2v/stamp-test-virt-p2v-pxe-data-files /p2v/stamp-test-virt-p2v-pxe-hostkey /p2v/stamp-test-virt-p2v-pxe-kernel diff --git a/generator/Makefile.am b/generator/Makefile.am index c2d10966a..d026e9558 100644 --- a/generator/Makefile.am +++ b/generator/Makefile.am @@ -101,6 +101,8 @@ sources = \ proc_nr.mli \ python.ml \ python.mli \ + p2v_config.ml \ + p2v_config.mli \ ruby.ml \ ruby.mli \ structs.ml \ @@ -165,6 +167,7 @@ objects = \ errnostring.cmo \ customize.cmo \ UEFI.cmo \ + p2v_config.cmo \ main.cmo EXTRA_DIST = $(sources) files-generated.txt diff --git a/generator/main.ml b/generator/main.ml index e51313779..ecc551f72 100644 --- a/generator/main.ml +++ b/generator/main.ml @@ -363,6 +363,11 @@ Run it from the top source directory using the command output_to "customize/customize-options.pod" Customize.generate_customize_options_pod; + output_to "p2v/p2v-config.h" + P2v_config.generate_p2v_config_h; + output_to "p2v/config.c" + P2v_config.generate_p2v_config_c; + (* Generate the list of files generated -- last. *) printf "generated %d lines of code\n" (get_lines_generated ()); let files = List.sort compare (get_files_generated ()) in diff --git a/generator/p2v_config.ml b/generator/p2v_config.ml new file mode 100644 index 000000000..1f998fd7c --- /dev/null +++ b/generator/p2v_config.ml @@ -0,0 +1,389 @@ +(* libguestfs + * Copyright (C) 2018 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 + *) + +(* Please read generator/README first. *) + +open Printf + +open Std_utils +open Docstrings +open Pr + +let generate_header = generate_header ~inputs:["generator/p2v_config.ml"] + +type enum_choice = string * string (* name, comment *) +type enum = string * enum_choice list + +type config_entry + | ConfigString of string + | ConfigInt of string * int (* field name, initial value *) + | ConfigUnsigned of string + | ConfigUInt64 of string + | ConfigEnum of string + | ConfigBool of string + | ConfigStringList of string + | ConfigSection of string * config_entry list + +(* Enums. *) +let enums = [ + "basis", [ + "BASIS_UNKNOWN", "RTC could not be read"; + "BASIS_UTC", "RTC is either UTC or an offset from UTC"; + "BASIS_LOCALTIME", "RTC is localtime"; + ]; + "output_allocation", [ + "OUTPUT_ALLOCATION_NONE", "output allocation not set"; + "OUTPUT_ALLOCATION_SPARSE", "sparse"; + "OUTPUT_ALLOCATION_PREALLOCATED", "preallocated"; + ]; +] + +(* Configuration fields. *) +let fields = [ + ConfigString "server"; + ConfigInt ("port", 22); + ConfigString "username"; + ConfigString "password"; + ConfigString "identity_url"; + ConfigString "identity_file"; + ConfigBool "identity_file_needs_update"; + ConfigBool "sudo"; + ConfigString "guestname"; + ConfigInt ("vcpus", 0); + ConfigUInt64 "memory"; + ConfigSection ("cpu", [ + ConfigString "vendor"; + ConfigString "model"; + ConfigUnsigned "sockets"; + ConfigUnsigned "cores"; + ConfigUnsigned "threads"; + ConfigBool "acpi"; + ConfigBool "apic"; + ConfigBool "pae"; + ]); + ConfigSection ("rtc", [ + ConfigEnum "basis"; + ConfigInt ("offset", 0); + ]); + ConfigStringList "disks"; + ConfigStringList "removable"; + ConfigStringList "interfaces"; + ConfigStringList "network_map"; + ConfigString "output"; + ConfigEnum "output_allocation"; + ConfigString "output_connection"; + ConfigString "output_format"; + ConfigString "output_storage"; +] + +let name_of_config_entry = function + | ConfigString n + | ConfigInt (n, _) + | ConfigUnsigned n + | ConfigUInt64 n + | ConfigEnum n + | ConfigBool n + | ConfigStringList n + | ConfigSection (n, _) -> n + +let rec generate_p2v_config_h () + generate_header CStyle GPLv2plus; + + pr "\ +#ifndef GUESTFS_P2V_CONFIG_H +#define GUESTFS_P2V_CONFIG_H + +#include <stdbool.h> +#include <stdint.h> + +"; + + (* Generate enums. *) + List.iter ( + fun (name, fields) -> + pr "enum %s {\n" name; + List.iter ( + fun (n, comment) -> + pr " %-25s /* %s */\n" (n ^ ",") comment + ) fields; + pr "};\n"; + pr "\n" + ) enums; + + (* Generate struct config. *) + generate_config_struct "config" fields; + + pr "\ +extern struct config *new_config (void); +extern struct config *copy_config (struct config *); +extern void free_config (struct config *); +extern void print_config (struct config *, FILE *); + +#endif /* GUESTFS_P2V_CONFIG_H */ +" + +and generate_config_struct name fields + (* If there are any ConfigSection (sub-structs) in any of the + * fields then output those first. + *) + List.iter ( + function + | ConfigSection (name, fields) -> + generate_config_struct (name ^ "_config") fields + | _ -> () + ) fields; + + (* Now generate this struct. *) + pr "struct %s {\n" name; + List.iter ( + function + | ConfigString n -> pr " char *%s;\n" n + | ConfigInt (n, _) -> pr " int %s;\n" n + | ConfigUnsigned n -> pr " unsigned %s;\n" n + | ConfigUInt64 n -> pr " uint64_t %s;\n" n + | ConfigEnum n -> pr " enum %s %s;\n" n n + | ConfigBool n -> pr " bool %s;\n" n + | ConfigStringList n -> pr " char **%s;\n" n + | ConfigSection (n, _) -> pr " struct %s_config %s;\n" n n + ) fields; + pr "};\n"; + pr "\n" + +let rec generate_p2v_config_c () + generate_header CStyle GPLv2plus; + + pr "\ +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <stdbool.h> +#include <inttypes.h> +#include <errno.h> +#include <error.h> + +#include \"p2v.h\" +#include \"p2v-config.h\" + +/** + * Allocate a new config struct. + */ +struct config * +new_config (void) +{ + struct config *c; + + c = calloc (1, sizeof *c); + if (c == NULL) + error (EXIT_FAILURE, errno, \"calloc\"); + +"; + + generate_field_initialization "c->" fields; + + pr "\ + + return c; +} + +/** + * Copy a config struct. + */ +struct config * +copy_config (struct config *old) +{ + struct config *c = new_config (); + + memcpy (c, old, sizeof *c); + + /* Need to deep copy strings and string lists. */ +"; + + generate_field_copy "c->" fields; + + pr "\ + + return c; +} + +/** + * Free a config struct. + */ +void +free_config (struct config *c) +{ + if (c == NULL) + return; + +"; + + generate_field_free "c->" fields; + +pr "\ +} + +"; + + List.iter ( + fun (name, fields) -> + pr "static void\n"; + pr "print_%s (enum %s v, FILE *fp)\n" name name; + pr "{\n"; + pr " switch (v) {\n"; + List.iter ( + fun (n, comment) -> + pr " case %s:\n" n; + pr " fprintf (fp, \"%s\");\n" comment; + pr " break;\n"; + ) fields; + pr " }\n"; + pr "}\n"; + pr "\n"; + ) enums; + + pr "\ +/** + * Print the conversion parameters and other important information. + */ +void +print_config (struct config *c, FILE *fp) +{ + size_t i; + + fprintf (fp, \"%%-20s %%s\\n\", \"local version\", PACKAGE_VERSION_FULL); + fprintf (fp, \"%%-20s %%s\\n\", \"remote version\", + v2v_version ? v2v_version : \"unknown\"); +"; + + generate_field_print None "c->" fields; + +pr "\ +} +" + +and generate_field_initialization v fields + List.iter ( + function + | ConfigInt (_, 0) -> () + | ConfigInt (n, i) -> + pr " %s%s = %d;\n" v n i + + | ConfigString _ + | ConfigUnsigned _ + | ConfigUInt64 _ + | ConfigEnum _ + | ConfigBool _ + | ConfigStringList _ -> () + + | ConfigSection (n, fields) -> + let v = sprintf "%s%s." v n in + generate_field_initialization v fields + ) fields + +and generate_field_copy v fields + List.iter ( + function + | ConfigString n -> + pr " if (%s%s) {\n" v n; + pr " %s%s = strdup (%s%s);\n" v n v n; + pr " if (%s%s == NULL)\n" v n; + pr " error (EXIT_FAILURE, errno, \"strdup: %%s\", \"%s\");\n" n; + pr " }\n"; + | ConfigStringList n -> + pr " if (%s%s) {\n" v n; + pr " %s%s = guestfs_int_copy_string_list (%s%s);\n" v n v n; + pr " if (%s%s == NULL)\n" v n; + pr " error (EXIT_FAILURE, errno, \"copy string list: %%s\", \"%s\");\n" n; + pr " }\n"; + + | ConfigInt _ + | ConfigUnsigned _ + | ConfigUInt64 _ + | ConfigEnum _ + | ConfigBool _ -> () + + | ConfigSection (n, fields) -> + let v = sprintf "%s%s." v n in + generate_field_copy v fields + ) fields + +and generate_field_free v fields + List.iter ( + function + | ConfigString n -> + pr " free (%s%s);\n" v n + | ConfigStringList n -> + pr " guestfs_int_free_string_list (%s%s);\n" v n + + | ConfigInt _ + | ConfigUnsigned _ + | ConfigUInt64 _ + | ConfigEnum _ + | ConfigBool _ -> () + + | ConfigSection (n, fields) -> + let v = sprintf "%s%s." v n in + generate_field_free v fields + ) fields + +and generate_field_print prefix v fields + List.iter ( + fun field -> + let printable_name + match prefix with + | None -> name_of_config_entry field + | Some prefix -> prefix ^ "." ^ name_of_config_entry field in + + match field with + | ConfigString n -> + pr " fprintf (fp, \"%%-20s %%s\\n\",\n"; + pr " \"%s\", %s%s ? %s%s : \"(none)\");\n" + printable_name v n v n + | ConfigInt (n, _) -> + pr " fprintf (fp, \"%%-20s %%d\\n\",\n"; + pr " \"%s\", %s%s);\n" printable_name v n + | ConfigUnsigned n -> + pr " fprintf (fp, \"%%-20s %%u\\n\",\n"; + pr " \"%s\", %s%s);\n" printable_name v n + | ConfigUInt64 n -> + pr " fprintf (fp, \"%%-20s %%\" PRIu64 \"\\n\",\n"; + pr " \"%s\", %s%s);\n" printable_name v n + | ConfigEnum n -> + pr " fprintf (fp, \"%%-20s \", \"%s\");\n" printable_name; + pr " print_%s (%s%s, fp);\n" n v n; + pr " fprintf (fp, \"\\n\");\n" + | ConfigBool n -> + pr " fprintf (fp, \"%%-20s %%s\\n\",\n"; + pr " \"%s\", %s%s ? \"true\" : \"false\");\n" + printable_name v n + | ConfigStringList n -> + pr " fprintf (fp, \"%%-20s\", \"%s\");\n" printable_name; + pr " if (%s%s) {\n" v n; + pr " for (i = 0; %s%s[i] != NULL; ++i)\n" v n; + pr " fprintf (fp, \" %%s\", %s%s[i]);\n" v n; + pr " }\n"; + pr " else\n"; + pr " fprintf (fp, \" (none)\\n\");\n"; + pr " fprintf (fp, \"\\n\");\n" + + | ConfigSection (n, fields) -> + let v = sprintf "%s%s." v n in + generate_field_print (Some printable_name) v fields + ) fields diff --git a/generator/p2v_config.mli b/generator/p2v_config.mli new file mode 100644 index 000000000..55d0363a3 --- /dev/null +++ b/generator/p2v_config.mli @@ -0,0 +1,20 @@ +(* libguestfs + * Copyright (C) 2009-2018 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 generate_p2v_config_h : unit -> unit +val generate_p2v_config_c : unit -> unit diff --git a/p2v/Makefile.am b/p2v/Makefile.am index 12b944a2f..f66c2a09b 100644 --- a/p2v/Makefile.am +++ b/p2v/Makefile.am @@ -18,7 +18,9 @@ include $(top_srcdir)/subdir-rules.mk generator_built = \ - about-authors.c + about-authors.c \ + config.c \ + p2v-config.h BUILT_SOURCES = \ $(generator_built) @@ -90,6 +92,7 @@ virt_p2v_SOURCES = \ main.c \ nbd.c \ p2v.h \ + p2v-config.h \ physical-xml.c \ rtc.c \ ssh.c \ diff --git a/p2v/config.c b/p2v/config.c deleted file mode 100644 index 49e0343d1..000000000 --- a/p2v/config.c +++ /dev/null @@ -1,208 +0,0 @@ -/* virt-p2v - * Copyright (C) 2009-2018 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. - */ - -#include <config.h> - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <inttypes.h> -#include <unistd.h> -#include <errno.h> -#include <error.h> -#include <locale.h> -#include <libintl.h> - -#include "p2v.h" - -struct config * -new_config (void) -{ - struct config *c; - - c = calloc (1, sizeof *c); - if (c == NULL) - error (EXIT_FAILURE, errno, "calloc"); - - c->port = 22; - - c->output_allocation = OUTPUT_ALLOCATION_NONE; - - return c; -} - -struct config * -copy_config (struct config *old) -{ - struct config *c = new_config (); - - memcpy (c, old, sizeof *c); - - /* Need to deep copy strings and string lists. */ - if (c->server) - c->server = strdup (c->server); - if (c->username) - c->username = strdup (c->username); - if (c->password) - c->password = strdup (c->password); - if (c->identity_url) - c->identity_url = strdup (c->identity_url); - if (c->identity_file) - c->identity_file = strdup (c->identity_file); - if (c->guestname) - c->guestname = strdup (c->guestname); - if (c->cpu.vendor) - c->cpu.vendor = strdup (c->cpu.vendor); - if (c->cpu.model) - c->cpu.model = strdup (c->cpu.model); - if (c->disks) - c->disks = guestfs_int_copy_string_list (c->disks); - if (c->removable) - c->removable = guestfs_int_copy_string_list (c->removable); - if (c->interfaces) - c->interfaces = guestfs_int_copy_string_list (c->interfaces); - if (c->network_map) - c->network_map = guestfs_int_copy_string_list (c->network_map); - if (c->output) - c->output = strdup (c->output); - if (c->output_connection) - c->output_connection = strdup (c->output_connection); - if (c->output_format) - c->output_format = strdup (c->output_format); - if (c->output_storage) - c->output_storage = strdup (c->output_storage); - - return c; -} - -void -free_config (struct config *c) -{ - free (c->server); - free (c->username); - free (c->password); - free (c->identity_url); - free (c->identity_file); - free (c->guestname); - free (c->cpu.vendor); - free (c->cpu.model); - guestfs_int_free_string_list (c->disks); - guestfs_int_free_string_list (c->removable); - guestfs_int_free_string_list (c->interfaces); - guestfs_int_free_string_list (c->network_map); - free (c->output); - free (c->output_connection); - free (c->output_format); - free (c->output_storage); - free (c); -} - -/** - * Print the conversion parameters and other important information. - */ -void -print_config (struct config *config, FILE *fp) -{ - size_t i; - - fprintf (fp, "local version . %s\n", PACKAGE_VERSION_FULL); - fprintf (fp, "remote version . %s\n", - v2v_version ? v2v_version : "unknown"); - fprintf (fp, "conversion server %s\n", - config->server ? config->server : "none"); - fprintf (fp, "port . . . . . . %d\n", config->port); - fprintf (fp, "username . . . . %s\n", - config->username ? config->username : "none"); - fprintf (fp, "password . . . . %s\n", - config->password && strlen (config->password) > 0 ? "***" : "none"); - fprintf (fp, "identity URL . . %s\n", - config->identity_url ? config->identity_url : "none"); - fprintf (fp, "sudo . . . . . . %s\n", - config->sudo ? "true" : "false"); - fprintf (fp, "guest name . . . %s\n", - config->guestname ? config->guestname : "none"); - fprintf (fp, "vcpus . . . . . %d\n", config->vcpus); - fprintf (fp, "memory . . . . . %" PRIu64 "\n", config->memory); - if (config->cpu.vendor) - fprintf (fp, "cpu vendor . . . %s\n", config->cpu.vendor); - if (config->cpu.model) - fprintf (fp, "cpu model . . . %s\n", config->cpu.model); - if (config->cpu.sockets > 0) - fprintf (fp, "cpu sockets . . %u\n", config->cpu.sockets); - if (config->cpu.cores > 0) - fprintf (fp, "cpu cores . . . %u\n", config->cpu.cores); - if (config->cpu.threads > 0) - fprintf (fp, "cpu threads . . %u\n", config->cpu.threads); - fprintf (fp, "flags . . . . . %s%s%s\n", - config->cpu.acpi ? " acpi" : "", - config->cpu.apic ? " apic" : "", - config->cpu.pae ? " pae" : ""); - fprintf (fp, "rtc offset . . . "); - switch (config->rtc.basis) { - case BASIS_UNKNOWN: - fprintf (fp, "unknown"); - break; - case BASIS_UTC: - fprintf (fp, "%d seconds from UTC", config->rtc.offset); - break; - case BASIS_LOCALTIME: - fprintf (fp, "%d seconds from localtime", config->rtc.offset); - break; - } - fprintf (fp, "\n"); - fprintf (fp, "disks . . . . . "); - if (config->disks != NULL) { - for (i = 0; config->disks[i] != NULL; ++i) - fprintf (fp, " %s", config->disks[i]); - } - fprintf (fp, "\n"); - fprintf (fp, "removable . . . "); - if (config->removable != NULL) { - for (i = 0; config->removable[i] != NULL; ++i) - fprintf (fp, " %s", config->removable[i]); - } - fprintf (fp, "\n"); - fprintf (fp, "interfaces . . . "); - if (config->interfaces != NULL) { - for (i = 0; config->interfaces[i] != NULL; ++i) - fprintf (fp, " %s", config->interfaces[i]); - } - fprintf (fp, "\n"); - fprintf (fp, "network map . . "); - if (config->network_map != NULL) { - for (i = 0; config->network_map[i] != NULL; ++i) - fprintf (fp, " %s", config->network_map[i]); - } - fprintf (fp, "\n"); - fprintf (fp, "output . . . . . %s\n", - config->output ? config->output : "none"); - fprintf (fp, "output alloc . . "); - switch (config->output_allocation) { - case OUTPUT_ALLOCATION_NONE: fprintf (fp, "none"); break; - case OUTPUT_ALLOCATION_SPARSE: fprintf (fp, "sparse"); break; - case OUTPUT_ALLOCATION_PREALLOCATED: fprintf (fp, "preallocated"); break; - default: fprintf (fp, "unknown? (%d)", config->output_allocation); - } - fprintf (fp, "\n"); - fprintf (fp, "output conn . . %s\n", - config->output_connection ? config->output_connection : "none"); - fprintf (fp, "output format . %s\n", - config->output_format ? config->output_format : "none"); - fprintf (fp, "output storage . %s\n", - config->output_storage ? config->output_storage : "none"); -} diff --git a/p2v/p2v.h b/p2v/p2v.h index b72a4832d..021ea2946 100644 --- a/p2v/p2v.h +++ b/p2v/p2v.h @@ -28,6 +28,7 @@ #define DEBUG_STDERR 1 #include "miniexpect.h" +#include "p2v-config.h" /* We don't use libguestfs directly here, and we don't link to it * either (in fact, we don't want libguestfs on the ISO). However @@ -59,61 +60,6 @@ extern int feature_colours_option; /* virt-p2v --colours option (used by ansi_* macros). */ extern int force_colour; -/* config.c */ -struct cpu_config { - char *vendor; /* eg. "Intel" */ - char *model; /* eg. "Broadwell" */ - unsigned sockets; /* number of sockets */ - unsigned cores; /* number of cores per socket */ - unsigned threads; /* number of hyperthreads per core */ - bool acpi; - bool apic; - bool pae; -}; - -struct rtc_config { - enum { - BASIS_UNKNOWN, /* RTC could not be read. */ - BASIS_UTC, /* RTC is either UTC or an offset from UTC. */ - BASIS_LOCALTIME, /* RTC is localtime. */ - } basis; - int offset; /* RTC seconds offset from basis. */ -}; - -struct config { - char *server; - int port; - char *username; - char *password; - char *identity_url; - char *identity_file; /* Used to cache the downloaded identity_url. */ - int identity_file_needs_update; - int sudo; - char *guestname; - int vcpus; - uint64_t memory; - struct cpu_config cpu; - struct rtc_config rtc; - char **disks; - char **removable; - char **interfaces; - char **network_map; - char *output; - int output_allocation; - char *output_connection; - char *output_format; - char *output_storage; -}; - -#define OUTPUT_ALLOCATION_NONE 0 -#define OUTPUT_ALLOCATION_SPARSE 1 -#define OUTPUT_ALLOCATION_PREALLOCATED 2 - -extern struct config *new_config (void); -extern struct config *copy_config (struct config *); -extern void free_config (struct config *); -extern void print_config (struct config *, FILE *); - /* cpuid.c */ extern void get_cpu_config (struct cpu_config *); diff --git a/p2v/test-virt-p2v-cmdline.sh b/p2v/test-virt-p2v-cmdline.sh index 770b7a825..f0077f750 100755 --- a/p2v/test-virt-p2v-cmdline.sh +++ b/p2v/test-virt-p2v-cmdline.sh @@ -33,21 +33,21 @@ $VG virt-p2v --cmdline='p2v.server=localhost p2v.port=123 p2v.username=user p2v. cat $out # Check the output contains what we expect. -grep "^conversion server.*localhost" $out +grep "^server.*localhost" $out grep "^port.*123" $out grep "^username.*user" $out grep "^sudo.*false" $out -grep "^guest name.*test" $out +grep "^guestname.*test" $out grep "^vcpus.*4" $out grep "^memory.*"$((1024*1024*1024)) $out grep "^disks.*sda sdb sdc" $out grep "^removable.*sdd" $out grep "^interfaces.*eth0 eth1" $out -grep "^network map.*em1:wired other" $out +grep "^network_map.*em1:wired other" $out grep "^output.*local" $out -grep "^output alloc.*sparse" $out -grep "^output conn.*qemu:///session" $out -grep "^output format.*raw" $out -grep "^output storage.*/var/tmp" $out +grep "^output_allocation.*sparse" $out +grep "^output_connection.*qemu:///session" $out +grep "^output_format.*raw" $out +grep "^output_storage.*/var/tmp" $out rm $out -- 2.17.1
Richard W.M. Jones
2018-Jun-29 12:16 UTC
[Libguestfs] [PATCH 2/3] p2v: Group configuration settings in sections.
Since the previous commit introduced configuration sections, we can now group more configuration settings together in these sections. This is just a renaming of certain fields. --- generator/p2v_config.ml | 46 ++++++++++------- p2v/conversion.c | 18 +++---- p2v/gui.c | 96 ++++++++++++++++++------------------ p2v/kernel.c | 44 ++++++++--------- p2v/main.c | 6 +-- p2v/ssh.c | 56 ++++++++++----------- p2v/test-virt-p2v-cmdline.sh | 18 +++---- 7 files changed, 146 insertions(+), 138 deletions(-) diff --git a/generator/p2v_config.ml b/generator/p2v_config.ml index 1f998fd7c..e0347d6c2 100644 --- a/generator/p2v_config.ml +++ b/generator/p2v_config.ml @@ -34,7 +34,7 @@ type config_entry | ConfigInt of string * int (* field name, initial value *) | ConfigUnsigned of string | ConfigUInt64 of string - | ConfigEnum of string + | ConfigEnum of string * string (* field name, enum *) | ConfigBool of string | ConfigStringList of string | ConfigSection of string * config_entry list @@ -55,14 +55,20 @@ let enums = [ (* Configuration fields. *) let fields = [ - ConfigString "server"; - ConfigInt ("port", 22); - ConfigString "username"; - ConfigString "password"; - ConfigString "identity_url"; - ConfigString "identity_file"; - ConfigBool "identity_file_needs_update"; - ConfigBool "sudo"; + ConfigSection ("remote", [ + ConfigString "server"; + ConfigInt ("port", 22); + ]); + ConfigSection ("auth", [ + ConfigString "username"; + ConfigString "password"; + ConfigSection ("identity", [ + ConfigString "url"; + ConfigString "file"; + ConfigBool "file_needs_update"; + ]); + ConfigBool "sudo"; + ]); ConfigString "guestname"; ConfigInt ("vcpus", 0); ConfigUInt64 "memory"; @@ -77,18 +83,20 @@ let fields = [ ConfigBool "pae"; ]); ConfigSection ("rtc", [ - ConfigEnum "basis"; + ConfigEnum ("basis", "basis"); ConfigInt ("offset", 0); ]); ConfigStringList "disks"; ConfigStringList "removable"; ConfigStringList "interfaces"; ConfigStringList "network_map"; - ConfigString "output"; - ConfigEnum "output_allocation"; - ConfigString "output_connection"; - ConfigString "output_format"; - ConfigString "output_storage"; + ConfigSection ("output", [ + ConfigString "type"; + ConfigEnum ("allocation", "output_allocation"); + ConfigString "connection"; + ConfigString "format"; + ConfigString "storage"; + ]); ] let name_of_config_entry = function @@ -96,7 +104,7 @@ let name_of_config_entry = function | ConfigInt (n, _) | ConfigUnsigned n | ConfigUInt64 n - | ConfigEnum n + | ConfigEnum (n, _) | ConfigBool n | ConfigStringList n | ConfigSection (n, _) -> n @@ -156,7 +164,7 @@ and generate_config_struct name fields | ConfigInt (n, _) -> pr " int %s;\n" n | ConfigUnsigned n -> pr " unsigned %s;\n" n | ConfigUInt64 n -> pr " uint64_t %s;\n" n - | ConfigEnum n -> pr " enum %s %s;\n" n n + | ConfigEnum (n, enum) -> pr " enum %s %s;\n" enum n | ConfigBool n -> pr " bool %s;\n" n | ConfigStringList n -> pr " char **%s;\n" n | ConfigSection (n, _) -> pr " struct %s_config %s;\n" n n @@ -365,9 +373,9 @@ and generate_field_print prefix v fields | ConfigUInt64 n -> pr " fprintf (fp, \"%%-20s %%\" PRIu64 \"\\n\",\n"; pr " \"%s\", %s%s);\n" printable_name v n - | ConfigEnum n -> + | ConfigEnum (n, enum) -> pr " fprintf (fp, \"%%-20s \", \"%s\");\n" printable_name; - pr " print_%s (%s%s, fp);\n" n v n; + pr " print_%s (%s%s, fp);\n" enum v n; pr " fprintf (fp, \"\\n\");\n" | ConfigBool n -> pr " fprintf (fp, \"%%-20s %%s\\n\",\n"; diff --git a/p2v/conversion.c b/p2v/conversion.c index b9da033db..dd056c69a 100644 --- a/p2v/conversion.c +++ b/p2v/conversion.c @@ -498,19 +498,19 @@ generate_wrapper_script (struct config *config, const char *remote_dir, /* The virt-v2v command, as a shell function called "v2v". */ fprintf (fp, "v2v ()\n"); fprintf (fp, "{\n"); - if (config->sudo) + if (config->auth.sudo) fprintf (fp, "sudo -n "); fprintf (fp, "virt-v2v -v -x"); if (feature_colours_option) fprintf (fp, " --colours"); fprintf (fp, " -i libvirtxml"); - if (config->output) { /* -o */ + if (config->output.type) { /* -o */ fprintf (fp, " -o "); - print_quoted (fp, config->output); + print_quoted (fp, config->output.type); } - switch (config->output_allocation) { /* -oa */ + switch (config->output.allocation) { /* -oa */ case OUTPUT_ALLOCATION_NONE: /* nothing */ break; @@ -524,14 +524,14 @@ generate_wrapper_script (struct config *config, const char *remote_dir, abort (); } - if (config->output_format) { /* -of */ + if (config->output.format) { /* -of */ fprintf (fp, " -of "); - print_quoted (fp, config->output_format); + print_quoted (fp, config->output.format); } - if (config->output_storage) { /* -os */ + if (config->output.storage) { /* -os */ fprintf (fp, " -os "); - print_quoted (fp, config->output_storage); + print_quoted (fp, config->output.storage); } fprintf (fp, " --root first"); @@ -562,7 +562,7 @@ generate_wrapper_script (struct config *config, const char *remote_dir, fprintf (fp, "# Log the version of virt-v2v (for information only).\n"); - if (config->sudo) + if (config->auth.sudo) fprintf (fp, "sudo -n "); fprintf (fp, "virt-v2v --version > v2v-version\n"); fprintf (fp, "\n"); diff --git a/p2v/gui.c b/p2v/gui.c index f596890c2..7ec2900a8 100644 --- a/p2v/gui.c +++ b/p2v/gui.c @@ -228,12 +228,12 @@ create_connection_dialog (struct config *config) hbox_new (server_hbox, FALSE, 4); server_entry = gtk_entry_new (); gtk_label_set_mnemonic_widget (GTK_LABEL (server_label), server_entry); - if (config->server != NULL) - gtk_entry_set_text (GTK_ENTRY (server_entry), config->server); + if (config->remote.server != NULL) + gtk_entry_set_text (GTK_ENTRY (server_entry), config->remote.server); port_colon_label = gtk_label_new (":"); port_entry = gtk_entry_new (); gtk_entry_set_width_chars (GTK_ENTRY (port_entry), 6); - snprintf (port_str, sizeof port_str, "%d", config->port); + snprintf (port_str, sizeof port_str, "%d", config->remote.port); gtk_entry_set_text (GTK_ENTRY (port_entry), port_str); gtk_box_pack_start (GTK_BOX (server_hbox), server_entry, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (server_hbox), port_colon_label, FALSE, FALSE, 0); @@ -247,8 +247,8 @@ create_connection_dialog (struct config *config) set_alignment (username_label, 1., 0.5); username_entry = gtk_entry_new (); gtk_label_set_mnemonic_widget (GTK_LABEL (username_label), username_entry); - if (config->username != NULL) - gtk_entry_set_text (GTK_ENTRY (username_entry), config->username); + if (config->auth.username != NULL) + gtk_entry_set_text (GTK_ENTRY (username_entry), config->auth.username); else gtk_entry_set_text (GTK_ENTRY (username_entry), "root"); table_attach (table, username_entry, @@ -265,8 +265,8 @@ create_connection_dialog (struct config *config) gtk_entry_set_input_purpose (GTK_ENTRY (password_entry), GTK_INPUT_PURPOSE_PASSWORD); #endif - if (config->password != NULL) - gtk_entry_set_text (GTK_ENTRY (password_entry), config->password); + if (config->auth.password != NULL) + gtk_entry_set_text (GTK_ENTRY (password_entry), config->auth.password); table_attach (table, password_entry, 1, 2, 2, 3, GTK_EXPAND|GTK_FILL, GTK_FILL, 4, 4); @@ -276,15 +276,15 @@ create_connection_dialog (struct config *config) set_alignment (identity_label, 1., 0.5); identity_entry = gtk_entry_new (); gtk_label_set_mnemonic_widget (GTK_LABEL (identity_label), identity_entry); - if (config->identity_url != NULL) - gtk_entry_set_text (GTK_ENTRY (identity_entry), config->identity_url); + if (config->auth.identity.url != NULL) + gtk_entry_set_text (GTK_ENTRY (identity_entry), config->auth.identity.url); table_attach (table, identity_entry, 1, 2, 3, 4, GTK_EXPAND|GTK_FILL, GTK_FILL, 4, 4); sudo_button gtk_check_button_new_with_mnemonic (_("Use su_do when running virt-v2v")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sudo_button), - config->sudo); + config->auth.sudo); table_attach (table, sudo_button, 1, 2, 4, 5, GTK_FILL, GTK_FILL, 4, 4); @@ -446,42 +446,42 @@ test_connection_clicked (GtkWidget *w, gpointer data) #endif /* Get the fields from the various widgets. */ - free (config->server); - config->server = strdup (gtk_entry_get_text (GTK_ENTRY (server_entry))); - if (STREQ (config->server, "")) { + free (config->remote.server); + config->remote.server = strdup (gtk_entry_get_text (GTK_ENTRY (server_entry))); + if (STREQ (config->remote.server, "")) { gtk_label_set_text (GTK_LABEL (spinner_message), _("error: No conversion server given.")); gtk_widget_grab_focus (server_entry); errors++; } port_str = gtk_entry_get_text (GTK_ENTRY (port_entry)); - if (sscanf (port_str, "%d", &config->port) != 1 || - config->port <= 0 || config->port >= 65536) { + if (sscanf (port_str, "%d", &config->remote.port) != 1 || + config->remote.port <= 0 || config->remote.port >= 65536) { gtk_label_set_text (GTK_LABEL (spinner_message), _("error: Invalid port number. If in doubt, use \"22\".")); gtk_widget_grab_focus (port_entry); errors++; } - free (config->username); - config->username = strdup (gtk_entry_get_text (GTK_ENTRY (username_entry))); - if (STREQ (config->username, "")) { + free (config->auth.username); + config->auth.username = strdup (gtk_entry_get_text (GTK_ENTRY (username_entry))); + if (STREQ (config->auth.username, "")) { gtk_label_set_text (GTK_LABEL (spinner_message), _("error: No user name. If in doubt, use \"root\".")); gtk_widget_grab_focus (username_entry); errors++; } - free (config->password); - config->password = strdup (gtk_entry_get_text (GTK_ENTRY (password_entry))); + free (config->auth.password); + config->auth.password = strdup (gtk_entry_get_text (GTK_ENTRY (password_entry))); - free (config->identity_url); + free (config->auth.identity.url); identity_str = gtk_entry_get_text (GTK_ENTRY (identity_entry)); if (identity_str && STRNEQ (identity_str, "")) - config->identity_url = strdup (identity_str); + config->auth.identity.url = strdup (identity_str); else - config->identity_url = NULL; - config->identity_file_needs_update = 1; + config->auth.identity.url = NULL; + config->auth.identity.file_needs_update = 1; - config->sudo = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (sudo_button)); + config->auth.sudo = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (sudo_button)); if (errors) return; @@ -839,8 +839,8 @@ create_conversion_dialog (struct config *config) oc_entry = gtk_entry_new (); gtk_label_set_mnemonic_widget (GTK_LABEL (oc_label), oc_entry); gtk_widget_set_tooltip_markup (oc_entry, _("For <b>libvirt</b> only, the libvirt connection URI, or leave blank to add the guest to the default libvirt instance on the conversion server. For others, leave this field blank.")); - if (config->output_connection != NULL) - gtk_entry_set_text (GTK_ENTRY (oc_entry), config->output_connection); + if (config->output.connection != NULL) + gtk_entry_set_text (GTK_ENTRY (oc_entry), config->output.connection); table_attach (output_tbl, oc_entry, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 1, 1); @@ -851,8 +851,8 @@ create_conversion_dialog (struct config *config) os_entry = gtk_entry_new (); gtk_label_set_mnemonic_widget (GTK_LABEL (os_label), os_entry); gtk_widget_set_tooltip_markup (os_entry, _("For <b>local</b>, put the directory name on the conversion server. For <b>rhv</b>, put the Export Storage Domain (server:/mountpoint). For others, leave this field blank.")); - if (config->output_storage != NULL) - gtk_entry_set_text (GTK_ENTRY (os_entry), config->output_storage); + if (config->output.storage != NULL) + gtk_entry_set_text (GTK_ENTRY (os_entry), config->output.storage); table_attach (output_tbl, os_entry, 1, 2, 2, 3, GTK_FILL, GTK_FILL, 1, 1); @@ -863,8 +863,8 @@ create_conversion_dialog (struct config *config) of_entry = gtk_entry_new (); gtk_label_set_mnemonic_widget (GTK_LABEL (of_label), of_entry); gtk_widget_set_tooltip_markup (of_entry, _("The output disk format, typically <b>raw</b> or <b>qcow2</b>. If blank, defaults to <b>raw</b>.")); - if (config->output_format != NULL) - gtk_entry_set_text (GTK_ENTRY (of_entry), config->output_format); + if (config->output.format != NULL) + gtk_entry_set_text (GTK_ENTRY (of_entry), config->output.format); table_attach (output_tbl, of_entry, 1, 2, 3, 4, GTK_FILL, GTK_FILL, 1, 1); @@ -878,7 +878,7 @@ create_conversion_dialog (struct config *config) "sparse"); gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (oa_combo), "preallocated"); - switch (config->output_allocation) { + switch (config->output.allocation) { case OUTPUT_ALLOCATION_PREALLOCATED: gtk_combo_box_set_active (GTK_COMBO_BOX (oa_combo), 1); break; @@ -1034,8 +1034,8 @@ repopulate_output_combo (struct config *config) size_t i; /* Which driver is currently selected? */ - if (config && config->output) - output = strdup (config->output); + if (config && config->output.type) + output = strdup (config->output.type); else output = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (o_combo)); @@ -1981,40 +1981,40 @@ start_conversion_clicked (GtkWidget *w, gpointer data) set_network_map_from_ui (config); /* Output selection. */ - free (config->output); - config->output + free (config->output.type); + config->output.type gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (o_combo)); - config->output_allocation = OUTPUT_ALLOCATION_NONE; + config->output.allocation = OUTPUT_ALLOCATION_NONE; str2 = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (oa_combo)); if (str2) { if (STREQ (str2, "sparse")) - config->output_allocation = OUTPUT_ALLOCATION_SPARSE; + config->output.allocation = OUTPUT_ALLOCATION_SPARSE; else if (STREQ (str2, "preallocated")) - config->output_allocation = OUTPUT_ALLOCATION_PREALLOCATED; + config->output.allocation = OUTPUT_ALLOCATION_PREALLOCATED; free (str2); } - free (config->output_connection); + free (config->output.connection); str = gtk_entry_get_text (GTK_ENTRY (oc_entry)); if (str && STRNEQ (str, "")) - config->output_connection = strdup (str); + config->output.connection = strdup (str); else - config->output_connection = NULL; + config->output.connection = NULL; - free (config->output_format); + free (config->output.format); str = gtk_entry_get_text (GTK_ENTRY (of_entry)); if (str && STRNEQ (str, "")) - config->output_format = strdup (str); + config->output.format = strdup (str); else - config->output_format = NULL; + config->output.format = NULL; - free (config->output_storage); + free (config->output.storage); str = gtk_entry_get_text (GTK_ENTRY (os_entry)); if (str && STRNEQ (str, "")) - config->output_storage = strdup (str); + config->output.storage = strdup (str); else - config->output_storage = NULL; + config->output.storage = NULL; /* Display the UI for conversion. */ show_running_dialog (); diff --git a/p2v/kernel.c b/p2v/kernel.c index 5da80808b..4f999755e 100644 --- a/p2v/kernel.c +++ b/p2v/kernel.c @@ -49,39 +49,39 @@ update_config_from_kernel_cmdline (struct config *config, char **cmdline) p = get_cmdline_key (cmdline, "p2v.server"); if (p) { - free (config->server); - config->server = strdup (p); + free (config->remote.server); + config->remote.server = strdup (p); } p = get_cmdline_key (cmdline, "p2v.port"); if (p) { - if (sscanf (p, "%d", &config->port) != 1) + if (sscanf (p, "%d", &config->remote.port) != 1) error (EXIT_FAILURE, 0, "cannot parse p2v.port from kernel command line"); } p = get_cmdline_key (cmdline, "p2v.username"); if (p) { - free (config->username); - config->username = strdup (p); + free (config->auth.username); + config->auth.username = strdup (p); } p = get_cmdline_key (cmdline, "p2v.password"); if (p) { - free (config->password); - config->password = strdup (p); + free (config->auth.password); + config->auth.password = strdup (p); } p = get_cmdline_key (cmdline, "p2v.identity"); if (p) { - free (config->identity_url); - config->identity_url = strdup (p); - config->identity_file_needs_update = 1; + free (config->auth.identity.url); + config->auth.identity.url = strdup (p); + config->auth.identity.file_needs_update = 1; } p = get_cmdline_key (cmdline, "p2v.sudo"); if (p) - config->sudo = 1; + config->auth.sudo = 1; p = get_cmdline_key (cmdline, "p2v.name"); if (p) { @@ -153,16 +153,16 @@ update_config_from_kernel_cmdline (struct config *config, char **cmdline) p = get_cmdline_key (cmdline, "p2v.o"); if (p) { - free (config->output); - config->output = strdup (p); + free (config->output.type); + config->output.type = strdup (p); } p = get_cmdline_key (cmdline, "p2v.oa"); if (p) { if (STREQ (p, "sparse")) - config->output_allocation = OUTPUT_ALLOCATION_SPARSE; + config->output.allocation = OUTPUT_ALLOCATION_SPARSE; else if (STREQ (p, "preallocated")) - config->output_allocation = OUTPUT_ALLOCATION_PREALLOCATED; + config->output.allocation = OUTPUT_ALLOCATION_PREALLOCATED; else fprintf (stderr, "%s: warning: don't know what p2v.oa=%s means\n", getprogname (), p); @@ -170,20 +170,20 @@ update_config_from_kernel_cmdline (struct config *config, char **cmdline) p = get_cmdline_key (cmdline, "p2v.oc"); if (p) { - free (config->output_connection); - config->output_connection = strdup (p); + free (config->output.connection); + config->output.connection = strdup (p); } p = get_cmdline_key (cmdline, "p2v.of"); if (p) { - free (config->output_format); - config->output_format = strdup (p); + free (config->output.format); + config->output.format = strdup (p); } p = get_cmdline_key (cmdline, "p2v.os"); if (p) { - free (config->output_storage); - config->output_storage = strdup (p); + free (config->output.storage); + config->output.storage = strdup (p); } /* Undocumented command line parameter used for testing command line @@ -216,7 +216,7 @@ kernel_conversion (struct config *config, char **cmdline, int cmdline_source) error (EXIT_FAILURE, 0, "error opening control connection to %s:%d: %s", - config->server, config->port, err); + config->remote.server, config->remote.port, err); } } diff --git a/p2v/main.c b/p2v/main.c index 3c8572bda..a5f13924e 100644 --- a/p2v/main.c +++ b/p2v/main.c @@ -249,7 +249,7 @@ main (int argc, char *argv[]) /* If p2v.server exists, then we use the non-interactive kernel * conversion. Otherwise we run the GUI. */ - if (config->server != NULL) + if (config->remote.server != NULL) kernel_conversion (config, cmdline, cmdline_source); else { if (!gui_possible) @@ -372,8 +372,8 @@ set_config_defaults (struct config *config) /* Default output drops the guest onto /var/tmp on the conversion * server, a hopefully safe default. */ - config->output = strdup ("local"); - config->output_storage = strdup ("/var/tmp"); + config->output.type = strdup ("local"); + config->output.storage = strdup ("/var/tmp"); } static int diff --git a/p2v/ssh.c b/p2v/ssh.c index 15f53b692..db43c42a3 100644 --- a/p2v/ssh.c +++ b/p2v/ssh.c @@ -276,7 +276,7 @@ curl_download (const char *url, const char *local_file) } /** - * Re-cache the C<config-E<gt>identity_url> if needed. + * Re-cache the C<config-E<gt>identity.url> if needed. */ static int cache_ssh_identity (struct config *config) @@ -284,25 +284,25 @@ cache_ssh_identity (struct config *config) int fd; /* If it doesn't need downloading, return. */ - if (config->identity_url == NULL || - !config->identity_file_needs_update) + if (config->auth.identity.url == NULL || + !config->auth.identity.file_needs_update) return 0; /* Generate a random filename. */ - free (config->identity_file); - config->identity_file = strdup ("/tmp/id.XXXXXX"); - if (config->identity_file == NULL) + free (config->auth.identity.file); + config->auth.identity.file = strdup ("/tmp/id.XXXXXX"); + if (config->auth.identity.file == NULL) error (EXIT_FAILURE, errno, "strdup"); - fd = mkstemp (config->identity_file); + fd = mkstemp (config->auth.identity.file); if (fd == -1) error (EXIT_FAILURE, errno, "mkstemp"); close (fd); /* Curl download URL to file. */ - if (curl_download (config->identity_url, config->identity_file) == -1) { - free (config->identity_file); - config->identity_file = NULL; - config->identity_file_needs_update = 1; + if (curl_download (config->auth.identity.url, config->auth.identity.file) == -1) { + free (config->auth.identity.file); + config->auth.identity.file = NULL; + config->auth.identity.file_needs_update = 1; return -1; } @@ -343,14 +343,14 @@ start_ssh (unsigned spawn_flags, struct config *config, return NULL; /* Are we using password or identity authentication? */ - using_password_auth = config->identity_file == NULL; + using_password_auth = config->auth.identity.file == NULL; ADD_ARG (argv, i, "ssh"); ADD_ARG (argv, i, "-p"); /* Port. */ - snprintf (port_str, sizeof port_str, "%d", config->port); + snprintf (port_str, sizeof port_str, "%d", config->remote.port); ADD_ARG (argv, i, port_str); ADD_ARG (argv, i, "-l"); /* Username. */ - ADD_ARG (argv, i, config->username ? config->username : "root"); + ADD_ARG (argv, i, config->auth.username ? config->auth.username : "root"); ADD_ARG (argv, i, "-o"); /* Host key will always be novel. */ ADD_ARG (argv, i, "StrictHostKeyChecking=no"); ADD_ARG (argv, i, "-o"); /* ConnectTimeout */ @@ -371,13 +371,13 @@ start_ssh (unsigned spawn_flags, struct config *config, ADD_ARG (argv, i, "-o"); ADD_ARG (argv, i, "PreferredAuthentications=publickey"); ADD_ARG (argv, i, "-i"); - ADD_ARG (argv, i, config->identity_file); + ADD_ARG (argv, i, config->auth.identity.file); } if (extra_args != NULL) { for (size_t j = 0; extra_args[j] != NULL; ++j) ADD_ARG (argv, i, extra_args[j]); } - ADD_ARG (argv, i, config->server); /* Conversion server. */ + ADD_ARG (argv, i, config->remote.server); /* Conversion server. */ ADD_ARG (argv, i, NULL); #if DEBUG_STDERR @@ -408,7 +408,7 @@ start_ssh (unsigned spawn_flags, struct config *config, mexp_set_timeout (h, SSH_TIMEOUT + 20); if (using_password_auth && - config->password && strlen (config->password) > 0) { + config->auth.password && strlen (config->auth.password) > 0) { CLEANUP_FREE char *ssh_message = NULL; /* Wait for the password prompt. */ @@ -420,7 +420,7 @@ start_ssh (unsigned spawn_flags, struct config *config, { 0 } }, ovector, ovecsize)) { case 100: /* Got password prompt. */ - if (mexp_printf_password (h, "%s", config->password) == -1 || + if (mexp_printf_password (h, "%s", config->auth.password) == -1 || mexp_printf (h, "\n") == -1) { set_ssh_mexp_error ("mexp_printf"); mexp_close (h); @@ -605,11 +605,11 @@ scp_file (struct config *config, const char *target, const char *local, ...) return -1; /* Are we using password or identity authentication? */ - using_password_auth = config->identity_file == NULL; + using_password_auth = config->auth.identity.file == NULL; ADD_ARG (argv, i, "scp"); ADD_ARG (argv, i, "-P"); /* Port. */ - snprintf (port_str, sizeof port_str, "%d", config->port); + snprintf (port_str, sizeof port_str, "%d", config->remote.port); ADD_ARG (argv, i, port_str); ADD_ARG (argv, i, "-o"); /* Host key will always be novel. */ ADD_ARG (argv, i, "StrictHostKeyChecking=no"); @@ -627,7 +627,7 @@ scp_file (struct config *config, const char *target, const char *local, ...) ADD_ARG (argv, i, "-o"); ADD_ARG (argv, i, "PreferredAuthentications=publickey"); ADD_ARG (argv, i, "-i"); - ADD_ARG (argv, i, config->identity_file); + ADD_ARG (argv, i, config->auth.identity.file); } /* Source files or directories. @@ -643,8 +643,8 @@ scp_file (struct config *config, const char *target, const char *local, ...) * "username@server:target". */ if (asprintf (&remote, "%s@%s:%s", - config->username ? config->username : "root", - config->server, target) == -1) + config->auth.username ? config->auth.username : "root", + config->remote.server, target) == -1) error (EXIT_FAILURE, errno, "asprintf"); ADD_ARG (argv, i, remote); @@ -678,7 +678,7 @@ scp_file (struct config *config, const char *target, const char *local, ...) mexp_set_timeout (h, SSH_TIMEOUT + 20); if (using_password_auth && - config->password && strlen (config->password) > 0) { + config->auth.password && strlen (config->auth.password) > 0) { CLEANUP_FREE char *ssh_message = NULL; /* Wait for the password prompt. */ @@ -690,7 +690,7 @@ scp_file (struct config *config, const char *target, const char *local, ...) { 0 } }, ovector, ovecsize)) { case 100: /* Got password prompt. */ - if (mexp_printf_password (h, "%s", config->password) == -1 || + if (mexp_printf_password (h, "%s", config->auth.password) == -1 || mexp_printf (h, "\n") == -1) { set_ssh_mexp_error ("mexp_printf"); mexp_close (h); @@ -793,7 +793,7 @@ test_connection (struct config *config) */ if (mexp_printf (h, "%svirt-v2v --version\n", - config->sudo ? "sudo -n " : "") == -1) { + config->auth.sudo ? "sudo -n " : "") == -1) { set_ssh_mexp_error ("mexp_printf"); mexp_close (h); return -1; @@ -818,7 +818,7 @@ test_connection (struct config *config) case 101: set_ssh_error ("sudo for user \"%s\" requires a password. Edit /etc/sudoers on the conversion server to ensure the \"NOPASSWD:\" option is set for this user.", - config->username); + config->auth.username); mexp_close (h); return -1; @@ -871,7 +871,7 @@ test_connection (struct config *config) /* Get virt-v2v features. See: v2v/cmdline.ml */ if (mexp_printf (h, "%svirt-v2v --machine-readable\n", - config->sudo ? "sudo -n " : "") == -1) { + config->auth.sudo ? "sudo -n " : "") == -1) { set_ssh_mexp_error ("mexp_printf"); mexp_close (h); return -1; diff --git a/p2v/test-virt-p2v-cmdline.sh b/p2v/test-virt-p2v-cmdline.sh index f0077f750..2fbca1eb5 100755 --- a/p2v/test-virt-p2v-cmdline.sh +++ b/p2v/test-virt-p2v-cmdline.sh @@ -33,10 +33,10 @@ $VG virt-p2v --cmdline='p2v.server=localhost p2v.port=123 p2v.username=user p2v. cat $out # Check the output contains what we expect. -grep "^server.*localhost" $out -grep "^port.*123" $out -grep "^username.*user" $out -grep "^sudo.*false" $out +grep "^remote\.server.*localhost" $out +grep "^remote\.port.*123" $out +grep "^auth\.username.*user" $out +grep "^auth\.sudo.*false" $out grep "^guestname.*test" $out grep "^vcpus.*4" $out grep "^memory.*"$((1024*1024*1024)) $out @@ -44,10 +44,10 @@ grep "^disks.*sda sdb sdc" $out grep "^removable.*sdd" $out grep "^interfaces.*eth0 eth1" $out grep "^network_map.*em1:wired other" $out -grep "^output.*local" $out -grep "^output_allocation.*sparse" $out -grep "^output_connection.*qemu:///session" $out -grep "^output_format.*raw" $out -grep "^output_storage.*/var/tmp" $out +grep "^output\.type.*local" $out +grep "^output\.allocation.*sparse" $out +grep "^output\.connection.*qemu:///session" $out +grep "^output\.format.*raw" $out +grep "^output\.storage.*/var/tmp" $out rm $out -- 2.17.1
Richard W.M. Jones
2018-Jun-29 12:16 UTC
[Libguestfs] [PATCH 3/3] p2v: Generate the code and docs for parsing the kernel command line.
As a side effect, a lot more fields are now settable on the kernel command line. Existing kernel command lines & corresponding documentation should still remain backwards compatible. --- .gitignore | 2 + generator/main.ml | 4 + generator/p2v_config.ml | 458 ++++++++++++++++++++++++++++++++++++++- generator/p2v_config.mli | 2 + p2v/Makefile.am | 8 +- p2v/kernel.c | 154 ------------- p2v/p2v.h | 4 +- p2v/virt-p2v.pod | 131 +---------- po-docs/language.mk | 8 + po-docs/podfiles | 1 + 10 files changed, 475 insertions(+), 297 deletions(-) diff --git a/.gitignore b/.gitignore index 4c0ff4e1e..d855459f3 100644 --- a/.gitignore +++ b/.gitignore @@ -435,6 +435,7 @@ Makefile.in /p2v/dependencies.debian /p2v/dependencies.redhat /p2v/dependencies.suse +/p2v/kernel-config.c /p2v/p2v-config.h /p2v/stamp-test-virt-p2v-pxe-data-files /p2v/stamp-test-virt-p2v-pxe-hostkey @@ -457,6 +458,7 @@ Makefile.in /p2v/virt-p2v.1 /p2v/virt-p2v.i686 /p2v/virt-p2v.img +/p2v/virt-p2v-kernel-config.pod /p2v/virt-p2v-make-disk /p2v/virt-p2v-make-disk.1 /p2v/virt-p2v-make-kickstart diff --git a/generator/main.ml b/generator/main.ml index ecc551f72..72f31ecab 100644 --- a/generator/main.ml +++ b/generator/main.ml @@ -367,6 +367,10 @@ Run it from the top source directory using the command P2v_config.generate_p2v_config_h; output_to "p2v/config.c" P2v_config.generate_p2v_config_c; + output_to "p2v/kernel-config.c" + P2v_config.generate_p2v_kernel_config_c; + output_to "p2v/virt-p2v-kernel-config.pod" + P2v_config.generate_p2v_kernel_config_pod; (* Generate the list of files generated -- last. *) printf "generated %d lines of code\n" (get_lines_generated ()); diff --git a/generator/p2v_config.ml b/generator/p2v_config.ml index e0347d6c2..11aec5ee3 100644 --- a/generator/p2v_config.ml +++ b/generator/p2v_config.ml @@ -26,7 +26,7 @@ open Pr let generate_header = generate_header ~inputs:["generator/p2v_config.ml"] -type enum_choice = string * string (* name, comment *) +type enum_choice = string * string * string (* name, cmdline, comment *) type enum = string * enum_choice list type config_entry @@ -39,17 +39,22 @@ type config_entry | ConfigStringList of string | ConfigSection of string * config_entry list +type manual_entry = { + shortopt : string; + description : string; +} + (* Enums. *) let enums = [ "basis", [ - "BASIS_UNKNOWN", "RTC could not be read"; - "BASIS_UTC", "RTC is either UTC or an offset from UTC"; - "BASIS_LOCALTIME", "RTC is localtime"; + "BASIS_UNKNOWN", "unknown", "RTC could not be read"; + "BASIS_UTC", "utc", "RTC is either UTC or an offset from UTC"; + "BASIS_LOCALTIME", "localtime", "RTC is localtime"; ]; "output_allocation", [ - "OUTPUT_ALLOCATION_NONE", "output allocation not set"; - "OUTPUT_ALLOCATION_SPARSE", "sparse"; - "OUTPUT_ALLOCATION_PREALLOCATED", "preallocated"; + "OUTPUT_ALLOCATION_NONE", "none", "output allocation not set"; + "OUTPUT_ALLOCATION_SPARSE", "sparse", "sparse"; + "OUTPUT_ALLOCATION_PREALLOCATED", "preallocated", "preallocated"; ]; ] @@ -99,6 +104,245 @@ let fields = [ ]); ] +(* Some /proc/cmdline p2v.* options were renamed when we introduced + * the generator. This map creates backwards compatibility mappings + * for these. + *) +let cmdline_aliases = [ + "p2v.remote.server", ["p2v.server"]; + "p2v.remote.port", ["p2v.port"]; + "p2v.auth.username", ["p2v.username"]; + "p2v.auth.password", ["p2v.password"]; + "p2v.auth.identity.url", ["p2v.identity"]; + "p2v.auth.sudo", ["p2v.sudo"]; + "p2v.guestname", ["p2v.name"]; + "p2v.network_map", ["p2v.network"]; + "p2v.output.type", ["p2v.o"]; + "p2v.output.allocation", ["p2v.oa"]; + "p2v.output.connection", ["p2v.oc"]; + "p2v.output.format", ["p2v.of"]; + "p2v.output.storage", ["p2v.os"]; +] + +(* Some config entries are not exposed on the kernel command line. *) +let cmdline_ignore = [ + "p2v.auth.identity.file"; + "p2v.auth.identity.file_needs_update"; +] + +(* Man page snippets for each kernel command line setting. *) +let cmdline_manual = [ + "p2v.remote.server", { + shortopt = "SERVER"; + description = " +The name or IP address of the conversion server. + +This is always required if you are using the kernel configuration +method. If virt-p2v does not find this on the kernel command line +then it switches to the GUI (interactive) configuration method."; + }; + "p2v.remote.port", { + shortopt = "PORT"; + description = " +The SSH port number on the conversion server (default: C<22>)."; + }; + "p2v.auth.username", { + shortopt = "USERNAME"; + description = " +The SSH username that we log in as on the conversion server +(default: C<root>)."; + }; + "p2v.auth.password", { + shortopt = "PASSWORD"; + description = " +The SSH password that we use to log in to the conversion server. + +The default is to try with no password. If this fails then virt-p2v +will ask the user to type the password (probably several times during +conversion). + +This setting is ignored if C<p2v.auth.identity.url> is present."; + }; + "p2v.auth.identity.url", { + shortopt = "URL"; + description = " +Provide a URL pointing to an SSH identity (private key) file. The URL +is interpreted by L<curl(1)> so any URL that curl supports can be used +here, including C<https://> and C<file://>. For more information on +using SSH identities, see L</SSH IDENTITIES> below. + +If C<p2v.auth.identity.url> is present, it overrides C<p2v.auth.password>. +There is no fallback."; + }; + "p2v.auth.sudo", { + shortopt = ""; (* ignored for booleans *) + description = " +Use C<p2v.sudo> to tell virt-p2v to use L<sudo(8)> to gain root +privileges on the conversion server after logging in as a non-root +user (default: do not use sudo)."; + }; + "p2v.guestname", { + shortopt = "GUESTNAME"; + description = " +The name of the guest that is created. The default is to try to +derive a name from the physical machine’s hostname (if possible) else +use a randomly generated name."; + }; + "p2v.vcpus", { + shortopt = "N"; + description = " +The number of virtual CPUs to give to the guest. The default is to +use the same as the number of physical CPUs."; + }; + "p2v.memory", { + shortopt = "n(M|G)"; + description = " +The size of the guest memory. You must specify the unit such as +megabytes or gigabytes by using for example C<p2v.memory=1024M> or +C<p2v.memory=1G>. + +The default is to use the same amount of RAM as on the physical +machine."; + }; + "p2v.cpu.vendor", { + shortopt = "VENDOR"; + description = " +The vCPU vendor, eg. \"Intel\" or \"AMD\". The default is to use +the same CPU vendor as the physical machine."; + }; + "p2v.cpu.model", { + shortopt = "MODEL"; + description = " +The vCPU model, eg. \"IvyBridge\". The default is to use the same +CPU model as the physical machine."; + }; + "p2v.cpu.sockets", { + shortopt = "N"; + description = " +Number of vCPU sockets to use. The default is to use the same as the +physical machine."; + }; + "p2v.cpu.cores", { + shortopt = "N"; + description = " +Number of vCPU cores to use. The default is to use the same as the +physical machine."; + }; + "p2v.cpu.threads", { + shortopt = "N"; + description = " +Number of vCPU hyperthreads to use. The default is to use the same +as the physical machine."; + }; + "p2v.cpu.acpi", { + shortopt = ""; (* ignored for booleans *) + description = " +Whether to enable ACPI in the remote virtual machine. The default is +to use the same as the physical machine."; + }; + "p2v.cpu.apic", { + shortopt = ""; (* ignored for booleans *) + description = " +Whether to enable APIC in the remote virtual machine. The default is +to use the same as the physical machine."; + }; + "p2v.cpu.pae", { + shortopt = ""; (* ignored for booleans *) + description = " +Whether to enable PAE in the remote virtual machine. The default is +to use the same as the physical machine."; + }; + "p2v.rtc.basis", { + shortopt = ""; (* ignored for enums. *) + description = " +Set the basis of the Real Time Clock in the virtual machine. The +default is to try to detect this setting from the physical machine."; + }; + "p2v.rtc.offset", { + shortopt = "[+|-]HOURS"; + description = " +The offset of the Real Time Clock from UTC. The default is to try +to detect this setting from the physical machine."; + }; + "p2v.disks", { + shortopt = "sda,sdb,..."; + description = " +A list of physical hard disks to convert, for example: + + p2v.disks=sda,sdc + +The default is to convert all local hard disks that are found."; + }; + "p2v.removable", { + shortopt = "sra,srb,..."; + description = " +A list of removable media to convert. The default is to create +virtual removable devices for every physical removable device found. +Note that the content of removable media is never copied over."; + }; + "p2v.interfaces", { + shortopt = "em1,..."; + description = " +A list of network interfaces to convert. The default is to create +virtual network interfaces for every physical network interface found."; + }; + "p2v.network_map", { + shortopt = "interface:target,..."; + description = " +Controls how network interfaces are connected to virtual networks on +the target hypervisor. The default is to connect all network +interfaces to the target C<default> network. + +You give a comma-separated list of C<interface:target> pairs, plus +optionally a default target. For example: + + p2v.network=em1:ovirtmgmt + +maps interface C<em1> to target network C<ovirtmgmt>. + + p2v.network=em1:ovirtmgmt,em2:management,other + +maps interface C<em1> to C<ovirtmgmt>, and C<em2> to C<management>, +and any other interface that is found to C<other>."; + }; + "p2v.output.type", { + shortopt = "(libvirt|local|...)"; + description = " +Set the output mode. This is the same as the virt-v2v I<-o> option. +See L<virt-v2v(1)/OPTIONS>. + +If not specified, the default is C<local>, and the converted guest is +written to F</var/tmp>."; + }; + "p2v.output.allocation", { + shortopt = ""; (* ignored for enums *) + description = " +Set the output allocation mode. This is the same as the virt-v2v +I<-oa> option. See L<virt-v2v(1)/OPTIONS>."; + }; + "p2v.output.connection", { + shortopt = "URI"; + description = " +Set the output connection libvirt URI. This is the same as the +virt-v2v I<-oc> option. See L<virt-v2v(1)/OPTIONS> and +L<http://libvirt.org/uri.html>"; + }; + "p2v.output.format", { + shortopt = "(raw|qcow2|...)"; + description = " +Set the output format. This is the same as the virt-v2v I<-of> +option. See L<virt-v2v(1)/OPTIONS>."; + }; + "p2v.output.storage", { + shortopt = "STORAGE"; + description = " +Set the output storage. This is the same as the virt-v2v I<-os> +option. See L<virt-v2v(1)/OPTIONS>. + +If not specified, the default is F</var/tmp> (on the conversion server)."; + }; +] + let name_of_config_entry = function | ConfigString n | ConfigInt (n, _) @@ -126,7 +370,7 @@ let rec generate_p2v_config_h () fun (name, fields) -> pr "enum %s {\n" name; List.iter ( - fun (n, comment) -> + fun (n, _, comment) -> pr " %-25s /* %s */\n" (n ^ ",") comment ) fields; pr "};\n"; @@ -256,9 +500,9 @@ pr "\ pr "{\n"; pr " switch (v) {\n"; List.iter ( - fun (n, comment) -> + fun (n, cmdline, _) -> pr " case %s:\n" n; - pr " fprintf (fp, \"%s\");\n" comment; + pr " fprintf (fp, \"%s\");\n" cmdline; pr " break;\n"; ) fields; pr " }\n"; @@ -395,3 +639,197 @@ and generate_field_print prefix v fields let v = sprintf "%s%s." v n in generate_field_print (Some printable_name) v fields ) fields + +let rec generate_p2v_kernel_config_c () + generate_header CStyle GPLv2plus; + + pr "\ +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> +#include <unistd.h> +#include <errno.h> +#include <error.h> + +#include \"xstrtol.h\" + +#include \"p2v.h\" +#include \"p2v-config.h\" + +/** + * Read the kernel command line and parse out any C<p2v.*> fields that + * we understand into the config struct. + */ +void +update_config_from_kernel_cmdline (struct config *c, char **cmdline) +{ + const char *p; + strtol_error xerr; + unsigned long long ull; + +"; + + generate_field_config "p2v" "c->" fields; + + pr " if (c->auth.identity.url != NULL) + c->auth.identity.file_needs_update = 1; + + /* Undocumented command line parameter used for testing command line + * parsing. + */ + p = get_cmdline_key (cmdline, \"p2v.dump_config_and_exit\"); + if (p) { + print_config (c, stdout); + exit (EXIT_SUCCESS); + } +} +" + +and generate_field_config prefix v fields + List.iter ( + function + | ConfigSection (n, fields) -> + let prefix = sprintf "%s.%s" prefix n in + let v = sprintf "%s%s." v n in + generate_field_config prefix v fields + + | field -> + let n = name_of_config_entry field in + let key = sprintf "%s.%s" prefix n in + + if not (List.mem key cmdline_ignore) then ( + (* Is there an alias for this field? *) + let aliases + try List.assoc key cmdline_aliases + with Not_found -> [] in + + pr " if ((p = get_cmdline_key (cmdline, \"%s\")) != NULL" key; + List.iter ( + fun alias -> + pr " ||\n"; + pr " (p = get_cmdline_key (cmdline, \"%s\")) != NULL" alias; + ) aliases; + pr ") {\n"; + + (* Parse the field. *) + (match field with + | ConfigString n -> + pr " free (%s%s);\n" v n; + pr " %s%s = strdup (p);\n" v n; + pr " if (%s%s == NULL)\n" v n; + pr " error (EXIT_FAILURE, errno, \"strdup\");\n" + | ConfigStringList n -> + pr " guestfs_int_free_string_list (%s%s);\n" v n; + pr " %s%s = guestfs_int_split_string (',', p);\n" v n; + pr " if (%s%s == NULL)\n" v n; + pr " error (EXIT_FAILURE, errno, \"strdup\");\n" + | ConfigInt (n, _) -> + pr " if (sscanf (p, \"%%d\", &%s%s) != 1)\n" v n; + pr " error (EXIT_FAILURE, errno,\n"; + pr " \"cannot parse %%s=%%s from the kernel command line\",\n"; + pr " %S, p);\n" key + | ConfigUnsigned n -> + pr " if (sscanf (p, \"%%u\", &%s%s) != 1)\n" v n; + pr " error (EXIT_FAILURE, errno,\n"; + pr " \"cannot parse %%s=%%s from the kernel command line\",\n"; + pr " %S, p);\n" key + | ConfigUInt64 n -> + pr " xerr = xstrtoull (p, NULL, 0, &ull, \"0kKMGTPEZY\");\n"; + pr " if (xerr != LONGINT_OK)\n"; + pr " error (EXIT_FAILURE, 0,\n"; + pr " \"cannot parse %%s=%%s from the kernel command line\",\n"; + pr " %S, p);\n" key; + pr " %s%s = ull;\n" v n + | ConfigEnum (n, enum) -> + let enum_choices + try List.assoc enum enums + with Not_found -> failwithf "cannot find ConfigEnum %s" enum in + pr " "; + List.iter ( + fun (name, cmdline, _) -> + pr "if (STREQ (p, \"%s\"))\n" cmdline; + pr " %s%s = %s;\n" v n name; + pr " else "; + ) enum_choices; + pr "{\n"; + pr " error (EXIT_FAILURE, 0,\n"; + pr " \"invalid value %%s=%%s from the kernel command line\",\n"; + pr " %S, p);\n" key; + pr " }\n" + | ConfigBool n -> + pr " %s%s = guestfs_int_is_true (p) || STREQ (p, \"\");\n" v n + + | ConfigSection _ -> assert false (* see above *) + ); + + pr " }\n"; + pr "\n"; + ) + ) fields + +let rec generate_p2v_kernel_config_pod () + generate_field_config_pod "p2v" fields + +and generate_field_config_pod prefix fields + List.iter ( + function + | ConfigSection (n, fields) -> + let prefix = sprintf "%s.%s" prefix n in + generate_field_config_pod prefix fields + + | field -> + let n = name_of_config_entry field in + let key = sprintf "%s.%s" prefix n in + + if not (List.mem key cmdline_ignore) then ( + let manual_entry + try List.assoc key cmdline_manual + with Not_found -> + failwithf "generator/p2v_config.ml: missing manual entry for %s" + key in + + (* For booleans there is no shortopt field. For enums + * we generate it. + *) + let shortopt + match field with + | ConfigBool _ -> + assert (manual_entry.shortopt = ""); + "" + | ConfigEnum (_, enum) -> + assert (manual_entry.shortopt = ""); + + let enum_choices + try List.assoc enum enums + with Not_found -> failwithf "cannot find ConfigEnum %s" enum in + "=(" ^ + String.concat "|" + (List.map (fun (_, cmdline, _) -> cmdline) + enum_choices) ^ + ")" + | ConfigString _ + | ConfigInt _ + | ConfigUnsigned _ + | ConfigUInt64 _ + | ConfigStringList _ + | ConfigSection _ -> "=" ^ manual_entry.shortopt in + + (* The description must not end with \n *) + if String.is_suffix manual_entry.description "\n" then + failwithf "generator/p2v_config.ml: description of %s must not end with \\n" + key; + + (* Is there an alias for this field? *) + let aliases + try List.assoc key cmdline_aliases + with Not_found -> [] in + List.iter ( + fun k -> pr "=item B<%s%s>\n\n" k shortopt + ) (key :: aliases); + + pr "%s\n\n" manual_entry.description + ) + ) fields diff --git a/generator/p2v_config.mli b/generator/p2v_config.mli index 55d0363a3..43a02e5f1 100644 --- a/generator/p2v_config.mli +++ b/generator/p2v_config.mli @@ -18,3 +18,5 @@ val generate_p2v_config_h : unit -> unit val generate_p2v_config_c : unit -> unit +val generate_p2v_kernel_config_c : unit -> unit +val generate_p2v_kernel_config_pod : unit -> unit diff --git a/p2v/Makefile.am b/p2v/Makefile.am index f66c2a09b..cfdec535d 100644 --- a/p2v/Makefile.am +++ b/p2v/Makefile.am @@ -20,7 +20,9 @@ include $(top_srcdir)/subdir-rules.mk generator_built = \ about-authors.c \ config.c \ - p2v-config.h + kernel-config.c \ + p2v-config.h \ + virt-p2v-kernel-config.pod BUILT_SOURCES = \ $(generator_built) @@ -89,6 +91,7 @@ virt_p2v_SOURCES = \ inhibit.c \ kernel.c \ kernel-cmdline.c \ + kernel-config.c \ main.c \ nbd.c \ p2v.h \ @@ -165,10 +168,11 @@ noinst_DATA = \ virt-p2v.1 $(top_builddir)/website/virt-p2v.1.html: stamp-virt-p2v.pod -stamp-virt-p2v.pod: virt-p2v.pod +stamp-virt-p2v.pod: virt-p2v.pod virt-p2v-kernel-config.pod $(PODWRAPPER) \ --man virt-p2v.1 \ --html $(top_builddir)/website/virt-p2v.1.html \ + --insert $(srcdir)/virt-p2v-kernel-config.pod:__KERNEL_CONFIG__ \ --license GPLv2+ \ --warning safe \ $< diff --git a/p2v/kernel.c b/p2v/kernel.c index 4f999755e..33fff0356 100644 --- a/p2v/kernel.c +++ b/p2v/kernel.c @@ -42,160 +42,6 @@ static void notify_ui_callback (int type, const char *data); static void run_command (const char *stage, const char *command); -void -update_config_from_kernel_cmdline (struct config *config, char **cmdline) -{ - const char *p; - - p = get_cmdline_key (cmdline, "p2v.server"); - if (p) { - free (config->remote.server); - config->remote.server = strdup (p); - } - - p = get_cmdline_key (cmdline, "p2v.port"); - if (p) { - if (sscanf (p, "%d", &config->remote.port) != 1) - error (EXIT_FAILURE, 0, - "cannot parse p2v.port from kernel command line"); - } - - p = get_cmdline_key (cmdline, "p2v.username"); - if (p) { - free (config->auth.username); - config->auth.username = strdup (p); - } - - p = get_cmdline_key (cmdline, "p2v.password"); - if (p) { - free (config->auth.password); - config->auth.password = strdup (p); - } - - p = get_cmdline_key (cmdline, "p2v.identity"); - if (p) { - free (config->auth.identity.url); - config->auth.identity.url = strdup (p); - config->auth.identity.file_needs_update = 1; - } - - p = get_cmdline_key (cmdline, "p2v.sudo"); - if (p) - config->auth.sudo = 1; - - p = get_cmdline_key (cmdline, "p2v.name"); - if (p) { - free (config->guestname); - config->guestname = strdup (p); - } - - p = get_cmdline_key (cmdline, "p2v.vcpus"); - if (p) { - if (sscanf (p, "%d", &config->vcpus) != 1) - error (EXIT_FAILURE, 0, - "cannot parse p2v.vcpus from kernel command line"); - } - - p = get_cmdline_key (cmdline, "p2v.memory"); - if (p) { - char mem_code; - - if (sscanf (p, "%" SCNu64 "%c", &config->memory, &mem_code) != 2) - error (EXIT_FAILURE, 0, - "cannot parse p2v.memory from kernel command line"); - config->memory *= 1024; - if (mem_code == 'M' || mem_code == 'm' - || mem_code == 'G' || mem_code == 'g') - config->memory *= 1024; - if (mem_code == 'G' || mem_code == 'g') - config->memory *= 1024; - if (mem_code != 'M' && mem_code != 'm' - && mem_code != 'G' && mem_code != 'g') - error (EXIT_FAILURE, 0, - "p2v.memory on kernel command line must be followed by 'G' or 'M'"); - } - - p = get_cmdline_key (cmdline, "p2v.disks"); - if (p) { - CLEANUP_FREE char *t; - - t = strdup (p); - guestfs_int_free_string_list (config->disks); - config->disks = guestfs_int_split_string (',', t); - } - - p = get_cmdline_key (cmdline, "p2v.removable"); - if (p) { - CLEANUP_FREE char *t; - - t = strdup (p); - guestfs_int_free_string_list (config->removable); - config->removable = guestfs_int_split_string (',', t); - } - - p = get_cmdline_key (cmdline, "p2v.interfaces"); - if (p) { - CLEANUP_FREE char *t; - - t = strdup (p); - guestfs_int_free_string_list (config->interfaces); - config->interfaces = guestfs_int_split_string (',', t); - } - - p = get_cmdline_key (cmdline, "p2v.network"); - if (p) { - CLEANUP_FREE char *t; - - t = strdup (p); - guestfs_int_free_string_list (config->network_map); - config->network_map = guestfs_int_split_string (',', t); - } - - p = get_cmdline_key (cmdline, "p2v.o"); - if (p) { - free (config->output.type); - config->output.type = strdup (p); - } - - p = get_cmdline_key (cmdline, "p2v.oa"); - if (p) { - if (STREQ (p, "sparse")) - config->output.allocation = OUTPUT_ALLOCATION_SPARSE; - else if (STREQ (p, "preallocated")) - config->output.allocation = OUTPUT_ALLOCATION_PREALLOCATED; - else - fprintf (stderr, "%s: warning: don't know what p2v.oa=%s means\n", - getprogname (), p); - } - - p = get_cmdline_key (cmdline, "p2v.oc"); - if (p) { - free (config->output.connection); - config->output.connection = strdup (p); - } - - p = get_cmdline_key (cmdline, "p2v.of"); - if (p) { - free (config->output.format); - config->output.format = strdup (p); - } - - p = get_cmdline_key (cmdline, "p2v.os"); - if (p) { - free (config->output.storage); - config->output.storage = strdup (p); - } - - /* Undocumented command line parameter used for testing command line - * parsing. - */ - p = get_cmdline_key (cmdline, "p2v.dump_config_and_exit"); - if (p) { - print_config (config, stdout); - exit (EXIT_SUCCESS); - } -} - /* Perform conversion using the kernel method. */ void kernel_conversion (struct config *config, char **cmdline, int cmdline_source) diff --git a/p2v/p2v.h b/p2v/p2v.h index 021ea2946..ee661514c 100644 --- a/p2v/p2v.h +++ b/p2v/p2v.h @@ -74,8 +74,10 @@ extern const char *get_cmdline_key (char **cmdline, const char *key); #define CMDLINE_SOURCE_COMMAND_LINE 1 /* --cmdline */ #define CMDLINE_SOURCE_PROC_CMDLINE 2 /* /proc/cmdline */ -/* kernel.c */ +/* kernel-config.c */ extern void update_config_from_kernel_cmdline (struct config *config, char **cmdline); + +/* kernel.c */ extern void kernel_conversion (struct config *, char **cmdline, int cmdline_source); /* gui.c */ diff --git a/p2v/virt-p2v.pod b/p2v/virt-p2v.pod index fc2e7d310..48548f8c6 100644 --- a/p2v/virt-p2v.pod +++ b/p2v/virt-p2v.pod @@ -302,136 +302,7 @@ You have to set some or all of the following command line arguments: =over 4 -=item B<p2v.server=SERVER> - -The name or IP address of the conversion server. - -This is always required if you are using the kernel configuration -method. If virt-p2v does not find this on the kernel command line -then it switches to the GUI (interactive) configuration method. - -=item B<p2v.port=NN> - -The SSH port number on the conversion server (default: C<22>). - -=item B<p2v.username=USERNAME> - -The SSH username that we log in as on the conversion server -(default: C<root>). - -=item B<p2v.password=PASSWORD> - -The SSH password that we use to log in to the conversion server. - -The default is to try with no password. If this fails then virt-p2v -will ask the user to type the password (probably several times during -conversion). - -This setting is ignored if C<p2v.identity> is present. - -=item B<p2v.identity=URL> - -Provide a URL pointing to an SSH identity (private key) file. The URL -is interpreted by L<curl(1)> so any URL that curl supports can be used -here, including C<https://> and C<file://>. For more information on -using SSH identities, see L</SSH IDENTITIES> below. - -If C<p2v.identity> is present, it overrides C<p2v.password>. There is -no fallback. - -=item B<p2v.sudo> - -Use C<p2v.sudo> to tell virt-p2v to use L<sudo(8)> to gain root -privileges on the conversion server after logging in as a non-root -user (default: do not use sudo). - -=item B<p2v.name=GUESTNAME> - -The name of the guest that is created. The default is to try to -derive a name from the physical machine’s hostname (if possible) else -use a randomly generated name. - -=item B<p2v.vcpus=NN> - -The number of virtual CPUs to give to the guest. The default is to -use the same as the number of physical CPUs. - -=item B<p2v.memory=NN(M|G)> - -The size of the guest memory. You must specify the unit as either -megabytes or gigabytes by using (eg) C<p2v.memory=1024M> or -C<p2v.memory=1G>. - -The default is to use the same amount of RAM as on the physical -machine. - -=item B<p2v.disks=sdX,sdY,..> - -A list of physical hard disks to convert, for example: - - p2v.disks=sda,sdc - -The default is to convert all local hard disks that are found. - -=item B<p2v.removable=srX,srY,..> - -A list of removable media to convert. The default is to create -virtual removable devices for every physical removable device found. -Note that the content of removable media is never copied over. - -=item B<p2v.interfaces=em1,..> - -A list of network interfaces to convert. The default is to create -virtual network interfaces for every physical network interface found. - -=item B<p2v.network=interface:target,...> - -Controls how network interfaces are connected to virtual networks on -the target hypervisor. The default is to connect all network -interfaces to the target C<default> network. - -You give a comma-separated list of C<interface:target> pairs, plus -optionally a default target. For example: - - p2v.network=em1:ovirtmgmt - -maps interface C<em1> to target network C<ovirtmgmt>. - - p2v.network=em1:ovirtmgmt,em2:management,other - -maps interface C<em1> to C<ovirtmgmt>, and C<em2> to C<management>, -and any other interface that is found to C<other>. - -=item B<p2v.o=[libvirt|local|...]> - -Set the output mode. This is the same as the virt-v2v I<-o> option. -See L<virt-v2v(1)/OPTIONS>. - -If not specified, the default is C<local>, and the converted guest is -written to F</var/tmp>. - -=item B<p2v.oa=sparse|preallocated> - -Set the output allocation mode. This is the same as the virt-v2v -I<-oa> option. See L<virt-v2v(1)/OPTIONS>. - -=item B<p2v.oc=...> - -Set the output connection libvirt URI. This is the same as the -virt-v2v I<-oc> option. See L<virt-v2v(1)/OPTIONS> and -L<http://libvirt.org/uri.html> - -=item B<p2v.of=raw|qcow2|...> - -Set the output format. This is the same as the virt-v2v I<-of> -option. See L<virt-v2v(1)/OPTIONS>. - -=item B<p2v.os=...> - -Set the output storage. This is the same as the virt-v2v I<-os> -option. See L<virt-v2v(1)/OPTIONS>. - -If not specified, the default is F</var/tmp> (on the conversion server). +__KERNEL_CONFIG__ =item B<p2v.pre=COMMAND> diff --git a/po-docs/language.mk b/po-docs/language.mk index 3eeb058e0..0163edab3 100644 --- a/po-docs/language.mk +++ b/po-docs/language.mk @@ -148,6 +148,14 @@ virt-sysprep.1: virt-sysprep.pod sysprep-extra-options.pod sysprep-operations.po --insert $(srcdir)/sysprep-operations.pod:__OPERATIONS__ \ $< +virt-p2v.1: virt-p2v.pod virt-p2v-kernel-config.pod + $(PODWRAPPER) \ + --no-strict-checks \ + --man $@ \ + --license GPLv2+ \ + --insert $(srcdir)/virt-p2v-kernel-config.pod:__KERNEL_CONFIG__ \ + $< + %.1: %.pod $(PODWRAPPER) \ --no-strict-checks \ diff --git a/po-docs/podfiles b/po-docs/podfiles index 31a3aca3a..b6bd39b68 100644 --- a/po-docs/podfiles +++ b/po-docs/podfiles @@ -53,6 +53,7 @@ ../lua/examples/guestfs-lua.pod ../make-fs/virt-make-fs.pod ../ocaml/examples/guestfs-ocaml.pod +../p2v/virt-p2v-kernel-config.pod ../p2v/virt-p2v-make-disk.pod ../p2v/virt-p2v-make-kickstart.pod ../p2v/virt-p2v-make-kiwi.pod -- 2.17.1
Possibly Parallel Threads
- [PATCH 0/6] p2v: start making it independent
- [PATCH 1/6] p2v: move kernel config to perl script
- [PATCH 0/2] Remove virt-p2v from libguestfs
- [p2v PATCH 00/11] Expose virt-v2v's "-oo"; re-enable openstack
- [p2v PATCH 02/11] Introduce "p2v.output.misc" for passing "-oo" options to virt-v2v