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.
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
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
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
participants (1)
-
Richard W.M. Jones