import libguestfs-1.40.2-25.module+el8.3.0+7421+642fe24f

This commit is contained in:
CentOS Sources 2020-11-03 06:58:07 -05:00 committed by Andrew Lukoshko
parent efeedb8128
commit 893b57ed4a
151 changed files with 7594 additions and 9111 deletions

4
.gitignore vendored
View File

@ -1,4 +1,4 @@
SOURCES/RHEV-Application-Provisioning-Tool.exe_4.43-3 SOURCES/RHEV-Application-Provisioning-Tool.exe_4.43-5
SOURCES/libguestfs-1.38.4.tar.gz SOURCES/libguestfs-1.40.2.tar.gz
SOURCES/libguestfs.keyring SOURCES/libguestfs.keyring
SOURCES/rhsrvany.exe SOURCES/rhsrvany.exe

View File

@ -1,4 +1,4 @@
ac8722917cc31c36836e241bd7a4beb5f8a8b0c8 SOURCES/RHEV-Application-Provisioning-Tool.exe_4.43-3 130adbc011dc0af736465b813c2b22a600c128c1 SOURCES/RHEV-Application-Provisioning-Tool.exe_4.43-5
15c8f487ee163374cb7be9436fb1bb697cef7d9e SOURCES/libguestfs-1.38.4.tar.gz 45755f0f73b503790974484053ff482f32665b13 SOURCES/libguestfs-1.40.2.tar.gz
1bbc40f501a7fef9eef2a39b701a71aee2fea7c4 SOURCES/libguestfs.keyring 1bbc40f501a7fef9eef2a39b701a71aee2fea7c4 SOURCES/libguestfs.keyring
2bd96e478fc004cd323b5bd754c856641877dac6 SOURCES/rhsrvany.exe 2bd96e478fc004cd323b5bd754c856641877dac6 SOURCES/rhsrvany.exe

View File

@ -1,974 +0,0 @@
From 21f0a22072f0543c416c440665bcf75ae09e6233 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Mon, 12 Feb 2018 11:24:06 +0100
Subject: [PATCH] Switch from YAJL to Jansson
While YAJL mostly works fine, it did not see any active development in
the last 3 years. OTOH, Jansson is another JSON C implementation, with
a very liberal license, and a much nicer API.
Hence, switch all of libguestfs from YAJL to Jansson:
- configure checks, and buildsystem in general
- packages pulled in the appliance
- actual implementations
- contrib scripts
- documentation
This also makes use of the better APIs available (e.g. json_object_get,
json_array_foreach, and json_object_foreach). This does not change the
API of our OCaml Yajl module.
(cherry picked from commit bd1c5c9f4dcf38458099db8a0bf4659a07ef055d)
---
appliance/packagelist.in | 13 ++--
builder/Makefile.am | 4 +-
builder/yajl-c.c | 66 ++++++++--------
contrib/p2v/aux-scripts/do-build.sh | 8 +-
contrib/p2v/build-p2v-iso.sh | 3 +-
daemon/Makefile.am | 4 +-
daemon/ldm.c | 115 ++++++++++++----------------
docs/guestfs-building.pod | 2 +-
lib/Makefile.am | 4 +-
lib/info.c | 113 +++++++++++----------------
lib/qemu.c | 64 ++++++----------
m4/guestfs-libraries.m4 | 4 +-
12 files changed, 169 insertions(+), 231 deletions(-)
diff --git a/appliance/packagelist.in b/appliance/packagelist.in
index 8ded2588a..f92a6ce95 100644
--- a/appliance/packagelist.in
+++ b/appliance/packagelist.in
@@ -35,6 +35,7 @@ ifelse(REDHAT,1,
hivex
iproute
iputils
+ jansson
kernel
libcap
libldm
@@ -51,7 +52,6 @@ ifelse(REDHAT,1,
systemd dnl for /sbin/reboot and udevd
vim-minimal
xz
- yajl
yara
zfs-fuse
)
@@ -82,12 +82,12 @@ dnl iproute has been renamed to iproute2
libc-bin
libcap2
libhivex0
+ libjansson4
libpcre3
libsystemd0
libsystemd-id128-0
libsystemd-journal0
libtirpc1
- libyajl2
libyara3
linux-image
dnl syslinux 'suggests' mtools, but in reality it's a hard dependency:
@@ -116,6 +116,7 @@ ifelse(ARCHLINUX,1,
hivex
iproute2
iputils
+ jansson
libcap
libtirpc
linux
@@ -131,7 +132,6 @@ ifelse(ARCHLINUX,1,
systemd
vim
xz
- yajl
yara
)
@@ -153,9 +153,9 @@ ifelse(SUSE,1,
iputils
libcap2
libhivex0
+ libjansson4
libselinux1
libtirpc3
- libyajl2
libyara3
mkisofs
ntfsprogs
@@ -177,6 +177,7 @@ ifelse(FRUGALWARE,1,
hfsplus
iproute2
iputils
+ jansson
kernel
libcap
libtirpc
@@ -188,7 +189,6 @@ ifelse(FRUGALWARE,1,
systemd
vim
xz
- yajl
xfsprogs-acl
xfsprogs-attr
gptfdisk
@@ -209,9 +209,9 @@ ifelse(MAGEIA,1,
iproute2
iputils
libcap
+ libjansson4
libldm
libtirpc
- libyajl
dnl syslinux uses mtools without depending on it
mtools
nilfs-utils
@@ -224,7 +224,6 @@ ifelse(MAGEIA,1,
systemd /* for /sbin/reboot and udevd */
vim-minimal
xz
- yajl
)
acl
diff --git a/builder/Makefile.am b/builder/Makefile.am
index e5872bdd9..c7b50778a 100644
--- a/builder/Makefile.am
+++ b/builder/Makefile.am
@@ -157,7 +157,7 @@ virt_builder_CFLAGS = \
$(LIBLZMA_CFLAGS) \
$(LIBTINFO_CFLAGS) \
$(LIBXML2_CFLAGS) \
- $(YAJL_CFLAGS)
+ $(JANSSON_CFLAGS)
BOBJECTS = $(SOURCES_ML:.ml=.cmo)
XOBJECTS = $(BOBJECTS:.cmo=.cmx)
@@ -211,7 +211,7 @@ OCAMLCLIBS = \
$(LIBCRYPT_LIBS) \
$(LIBLZMA_LIBS) \
$(LIBXML2_LIBS) \
- $(YAJL_LIBS) \
+ $(JANSSON_LIBS) \
$(LIBINTL) \
-lgnu
diff --git a/builder/yajl-c.c b/builder/yajl-c.c
index 3c2402e42..e53755f55 100644
--- a/builder/yajl-c.c
+++ b/builder/yajl-c.c
@@ -23,24 +23,17 @@
#include <caml/memory.h>
#include <caml/mlvalues.h>
-#include <yajl/yajl_tree.h>
+#include <jansson.h>
#include <stdio.h>
#include <string.h>
-/* GCC can't work out that the YAJL_IS_<foo> test is sufficient to
- * ensure that YAJL_GET_<foo> later doesn't return NULL.
- */
-#if defined(__GNUC__) && __GNUC__ >= 6 /* gcc >= 6 */
-#pragma GCC diagnostic ignored "-Wnull-dereference"
-#endif
-
#define Val_none (Val_int (0))
value virt_builder_yajl_tree_parse (value stringv);
static value
-convert_yajl_value (yajl_val val, int level)
+convert_json_t (json_t *val, int level)
{
CAMLparam0 ();
CAMLlocal4 (rv, lv, v, sv);
@@ -48,46 +41,51 @@ convert_yajl_value (yajl_val val, int level)
if (level > 20)
caml_invalid_argument ("too many levels of object/array nesting");
- if (YAJL_IS_OBJECT (val)) {
- const size_t len = YAJL_GET_OBJECT(val)->len;
+ if (json_is_object (val)) {
+ const size_t len = json_object_size (val);
size_t i;
+ const char *key;
+ json_t *jvalue;
rv = caml_alloc (1, 3);
lv = caml_alloc_tuple (len);
- for (i = 0; i < len; ++i) {
+ i = 0;
+ json_object_foreach (val, key, jvalue) {
v = caml_alloc_tuple (2);
- sv = caml_copy_string (YAJL_GET_OBJECT(val)->keys[i]);
+ sv = caml_copy_string (key);
Store_field (v, 0, sv);
- sv = convert_yajl_value (YAJL_GET_OBJECT(val)->values[i], level + 1);
+ sv = convert_json_t (jvalue, level + 1);
Store_field (v, 1, sv);
Store_field (lv, i, v);
+ ++i;
}
Store_field (rv, 0, lv);
- } else if (YAJL_IS_ARRAY (val)) {
- const size_t len = YAJL_GET_ARRAY(val)->len;
+ } else if (json_is_array (val)) {
+ const size_t len = json_array_size (val);
size_t i;
+ json_t *jvalue;
rv = caml_alloc (1, 4);
lv = caml_alloc_tuple (len);
- for (i = 0; i < len; ++i) {
- v = convert_yajl_value (YAJL_GET_ARRAY(val)->values[i], level + 1);
+ json_array_foreach (val, i, jvalue) {
+ v = convert_json_t (jvalue, level + 1);
Store_field (lv, i, v);
}
Store_field (rv, 0, lv);
- } else if (YAJL_IS_STRING (val)) {
+ } else if (json_is_string (val)) {
rv = caml_alloc (1, 0);
- v = caml_copy_string (YAJL_GET_STRING(val));
+ v = caml_copy_string (json_string_value (val));
Store_field (rv, 0, v);
- } else if (YAJL_IS_DOUBLE (val)) {
+ } else if (json_is_real (val)) {
rv = caml_alloc (1, 2);
- v = caml_copy_double (YAJL_GET_DOUBLE(val));
+ v = caml_copy_double (json_real_value (val));
Store_field (rv, 0, v);
- } else if (YAJL_IS_INTEGER (val)) {
+ } else if (json_is_integer (val)) {
rv = caml_alloc (1, 1);
- v = caml_copy_int64 (YAJL_GET_INTEGER(val));
+ v = caml_copy_int64 (json_integer_value (val));
Store_field (rv, 0, v);
- } else if (YAJL_IS_TRUE (val)) {
+ } else if (json_is_true (val)) {
rv = caml_alloc (1, 5);
Store_field (rv, 0, Val_true);
- } else if (YAJL_IS_FALSE (val)) {
+ } else if (json_is_false (val)) {
rv = caml_alloc (1, 5);
Store_field (rv, 0, Val_false);
} else
@@ -101,21 +99,21 @@ virt_builder_yajl_tree_parse (value stringv)
{
CAMLparam1 (stringv);
CAMLlocal1 (rv);
- yajl_val tree;
- char error_buf[256];
+ json_t *tree;
+ json_error_t err;
- tree = yajl_tree_parse (String_val (stringv), error_buf, sizeof error_buf);
+ tree = json_loads (String_val (stringv), JSON_DECODE_ANY, &err);
if (tree == NULL) {
- char buf[256 + sizeof error_buf];
- if (strlen (error_buf) > 0)
- snprintf (buf, sizeof buf, "JSON parse error: %s", error_buf);
+ char buf[256 + JSON_ERROR_TEXT_LENGTH];
+ if (strlen (err.text) > 0)
+ snprintf (buf, sizeof buf, "JSON parse error: %s", err.text);
else
snprintf (buf, sizeof buf, "unknown JSON parse error");
caml_invalid_argument (buf);
}
- rv = convert_yajl_value (tree, 1);
- yajl_tree_free (tree);
+ rv = convert_json_t (tree, 1);
+ json_decref (tree);
CAMLreturn (rv);
}
diff --git a/contrib/p2v/aux-scripts/do-build.sh b/contrib/p2v/aux-scripts/do-build.sh
index 5edb53d0e..dd6424bb4 100644
--- a/contrib/p2v/aux-scripts/do-build.sh
+++ b/contrib/p2v/aux-scripts/do-build.sh
@@ -53,8 +53,8 @@ case $osversion in
# This just forces configure to ignore these missing dependencies.
export LIBTINFO_CFLAGS=-D_GNU_SOURCE
export LIBTINFO_LIBS=-lncurses
- export YAJL_CFLAGS=-D_GNU_SOURCE
- export YAJL_LIBS=-lyajl
+ export JANSSON_CFLAGS=-D_GNU_SOURCE
+ export JANSSON_LIBS=-ljansson
# Remove some unsupported flags that the configure script hard codes.
sed -i -e 's/-fno-strict-overflow//' configure
sed -i -e 's/-Wno-strict-overflow//' configure
@@ -66,8 +66,8 @@ case $osversion in
# This just forces configure to ignore these missing dependencies.
export LIBTINFO_CFLAGS=-D_GNU_SOURCE
export LIBTINFO_LIBS=-lncurses
- export YAJL_CFLAGS=-D_GNU_SOURCE
- export YAJL_LIBS=-lyajl
+ export JANSSON_CFLAGS=-D_GNU_SOURCE
+ export JANSSON_LIBS=-ljansson
;;
esac
diff --git a/contrib/p2v/build-p2v-iso.sh b/contrib/p2v/build-p2v-iso.sh
index c80a1b134..ae25cebc8 100755
--- a/contrib/p2v/build-p2v-iso.sh
+++ b/contrib/p2v/build-p2v-iso.sh
@@ -86,7 +86,6 @@ done
# Various hacks for different versions of RHEL.
if=virtio
netdev=virtio-net-pci
-pkgs="$pkgs,yajl-devel"
declare -a epel
case $osversion in
rhel-5.*|centos-5.*)
@@ -105,10 +104,12 @@ case $osversion in
rhel-6.*|centos-6.*)
epel[0]="--run-command"
epel[1]="yum install -y --nogpgcheck https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm"
+ pkgs="$pkgs,jansson-devel"
;;
rhel-7.*|centos-7.*)
epel[0]="--run-command"
epel[1]="yum install -y --nogpgcheck https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm"
+ pkgs="$pkgs,jansson-devel"
;;
esac
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 6240f517d..d9ed5625e 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -218,7 +218,7 @@ guestfsd_LDADD = \
camldaemon.o \
$(ACL_LIBS) \
$(CAP_LIBS) \
- $(YAJL_LIBS) \
+ $(JANSSON_LIBS) \
$(SELINUX_LIBS) \
$(AUGEAS_LIBS) \
$(HIVEX_LIBS) \
@@ -256,7 +256,7 @@ guestfsd_CFLAGS = \
$(AUGEAS_CFLAGS) \
$(HIVEX_CFLAGS) \
$(SD_JOURNAL_CFLAGS) \
- $(YAJL_CFLAGS) \
+ $(JANSSON_CFLAGS) \
$(PCRE_CFLAGS)
# Parts of the daemon are written in OCaml. These are linked into a
diff --git a/daemon/ldm.c b/daemon/ldm.c
index 2f4d2aef3..be4fb9701 100644
--- a/daemon/ldm.c
+++ b/daemon/ldm.c
@@ -25,19 +25,12 @@
#include <sys/stat.h>
#include <string.h>
-#include <yajl/yajl_tree.h>
+#include <jansson.h>
#include "daemon.h"
#include "actions.h"
#include "optgroups.h"
-/* GCC can't work out that the YAJL_IS_<foo> test is sufficient to
- * ensure that YAJL_GET_<foo> later doesn't return NULL.
- */
-#if defined(__GNUC__) && GUESTFS_GCC_VERSION >= 60000 /* gcc >= 6 */
-#pragma GCC diagnostic ignored "-Wnull-dereference"
-#endif
-
int
optgroup_ldm_available (void)
{
@@ -72,44 +65,42 @@ do_ldmtool_remove_all (void)
return 0;
}
-static yajl_val
+static json_t *
parse_json (const char *json, const char *func)
{
- yajl_val tree;
- char parse_error[1024];
+ json_t *tree;
+ json_error_t err;
if (verbose)
fprintf (stderr, "%s: parsing json: %s\n", func, json);
- tree = yajl_tree_parse (json, parse_error, sizeof parse_error);
+ tree = json_loads (json, 0, &err);
if (tree == NULL) {
reply_with_error ("parse error: %s",
- strlen (parse_error) ? parse_error : "unknown error");
+ strlen (err.text) ? err.text : "unknown error");
return NULL;
}
- /* Caller should free this by doing 'yajl_tree_free (tree);'. */
+ /* Caller should free this by doing 'json_decref (tree);'. */
return tree;
}
#define TYPE_ERROR ((char **) -1)
static char **
-json_value_to_string_list (yajl_val node)
+json_value_to_string_list (json_t *node)
{
CLEANUP_FREE_STRINGSBUF DECLARE_STRINGSBUF (strs);
- yajl_val n;
- size_t i, len;
+ json_t *n;
+ size_t i;
- if (! YAJL_IS_ARRAY (node))
+ if (!json_is_array (node))
return TYPE_ERROR;
- len = YAJL_GET_ARRAY (node)->len;
- for (i = 0; i < len; ++i) {
- n = YAJL_GET_ARRAY (node)->values[i];
- if (! YAJL_IS_STRING (n))
+ json_array_foreach (node, i, n) {
+ if (!json_is_string (n))
return TYPE_ERROR;
- if (add_string (&strs, YAJL_GET_STRING (n)) == -1)
+ if (add_string (&strs, json_string_value (n)) == -1)
return NULL;
}
if (end_stringsbuf (&strs) == -1)
@@ -123,14 +114,14 @@ parse_json_get_string_list (const char *json,
const char *func, const char *cmd)
{
char **ret;
- yajl_val tree = NULL;
+ json_t *tree = NULL;
tree = parse_json (json, func);
if (tree == NULL)
return NULL;
ret = json_value_to_string_list (tree);
- yajl_tree_free (tree);
+ json_decref (tree);
if (ret == TYPE_ERROR) {
reply_with_error ("output of '%s' was not a JSON array of strings", cmd);
return NULL;
@@ -144,43 +135,40 @@ static char *
parse_json_get_object_string (const char *json, const char *key, int flags,
const char *func, const char *cmd)
{
- char *str, *ret;
- yajl_val tree = NULL, node;
- size_t i, len;
+ const char *str;
+ char *ret;
+ json_t *tree = NULL, *node;
tree = parse_json (json, func);
if (tree == NULL)
return NULL;
- if (! YAJL_IS_OBJECT (tree))
+ if (!json_is_object (tree))
+ goto bad_type;
+
+ node = json_object_get (tree, key);
+ if (node == NULL)
goto bad_type;
- len = YAJL_GET_OBJECT (tree)->len;
- for (i = 0; i < len; ++i) {
- if (STREQ (YAJL_GET_OBJECT (tree)->keys[i], key)) {
- node = YAJL_GET_OBJECT (tree)->values[i];
-
- if ((flags & GET_STRING_NULL_TO_EMPTY) && YAJL_IS_NULL (node))
- ret = strdup ("");
- else {
- str = YAJL_GET_STRING (node);
- if (str == NULL)
- goto bad_type;
- ret = strdup (str);
- }
- if (ret == NULL)
- reply_with_perror ("strdup");
-
- yajl_tree_free (tree);
-
- return ret;
- }
+ if ((flags & GET_STRING_NULL_TO_EMPTY) && json_is_null (node))
+ ret = strdup ("");
+ else {
+ str = json_string_value (node);
+ if (str == NULL)
+ goto bad_type;
+ ret = strndup (str, json_string_length (node));
}
+ if (ret == NULL)
+ reply_with_perror ("strdup");
+
+ json_decref (tree);
+
+ return ret;
bad_type:
reply_with_error ("output of '%s' was not a JSON object "
"containing a key '%s' of type string", cmd, key);
- yajl_tree_free (tree);
+ json_decref (tree);
return NULL;
}
@@ -189,33 +177,30 @@ parse_json_get_object_string_list (const char *json, const char *key,
const char *func, const char *cmd)
{
char **ret;
- yajl_val tree, node;
- size_t i, len;
+ json_t *tree, *node;
tree = parse_json (json, func);
if (tree == NULL)
return NULL;
- if (! YAJL_IS_OBJECT (tree))
+ if (!json_is_object (tree))
goto bad_type;
- len = YAJL_GET_OBJECT (tree)->len;
- for (i = 0; i < len; ++i) {
- if (STREQ (YAJL_GET_OBJECT (tree)->keys[i], key)) {
- node = YAJL_GET_OBJECT (tree)->values[i];
- ret = json_value_to_string_list (node);
- if (ret == TYPE_ERROR)
- goto bad_type;
- yajl_tree_free (tree);
- return ret;
- }
- }
+ node = json_object_get (tree, key);
+ if (node == NULL)
+ goto bad_type;
+
+ ret = json_value_to_string_list (node);
+ if (ret == TYPE_ERROR)
+ goto bad_type;
+ json_decref (tree);
+ return ret;
bad_type:
reply_with_error ("output of '%s' was not a JSON object "
"containing a key '%s' of type array of strings",
cmd, key);
- yajl_tree_free (tree);
+ json_decref (tree);
return NULL;
}
diff --git a/docs/guestfs-building.pod b/docs/guestfs-building.pod
index d350b1d73..2029429fd 100644
--- a/docs/guestfs-building.pod
+++ b/docs/guestfs-building.pod
@@ -172,7 +172,7 @@ I<Required>.
I<Required>.
-=item yajl E<ge> 2.0.4
+=item Jansson
I<Required>.
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 91c4e0a2e..d075174d9 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -141,7 +141,7 @@ libguestfs_la_CFLAGS = \
$(PCRE_CFLAGS) \
$(LIBVIRT_CFLAGS) \
$(LIBXML2_CFLAGS) \
- $(YAJL_CFLAGS)
+ $(JANSSON_CFLAGS)
libguestfs_la_LIBADD = \
../common/errnostring/liberrnostring.la \
@@ -152,7 +152,7 @@ libguestfs_la_LIBADD = \
$(PCRE_LIBS) \
$(LIBVIRT_LIBS) $(LIBXML2_LIBS) \
$(SELINUX_LIBS) \
- $(YAJL_LIBS) \
+ $(JANSSON_LIBS) \
../gnulib/lib/libgnu.la \
$(GETADDRINFO_LIB) \
$(HOSTENT_LIB) \
diff --git a/lib/info.c b/lib/info.c
index 93fadcd39..2eadc1c11 100644
--- a/lib/info.c
+++ b/lib/info.c
@@ -37,53 +37,46 @@
#include <sys/resource.h>
#endif
-#include <yajl/yajl_tree.h>
+#include <jansson.h>
#include "guestfs.h"
#include "guestfs-internal.h"
#include "guestfs-internal-actions.h"
#ifdef HAVE_ATTRIBUTE_CLEANUP
-#define CLEANUP_YAJL_TREE_FREE __attribute__((cleanup(cleanup_yajl_tree_free)))
+#define CLEANUP_JSON_T_DECREF __attribute__((cleanup(cleanup_json_t_decref)))
static void
-cleanup_yajl_tree_free (void *ptr)
+cleanup_json_t_decref (void *ptr)
{
- yajl_tree_free (* (yajl_val *) ptr);
+ json_decref (* (json_t **) ptr);
}
#else
-#define CLEANUP_YAJL_TREE_FREE
+#define CLEANUP_JSON_T_DECREF
#endif
-static yajl_val get_json_output (guestfs_h *g, const char *filename);
+static json_t *get_json_output (guestfs_h *g, const char *filename);
static void set_child_rlimits (struct command *);
char *
guestfs_impl_disk_format (guestfs_h *g, const char *filename)
{
- size_t i, len;
- CLEANUP_YAJL_TREE_FREE yajl_val tree = get_json_output (g, filename);
+ CLEANUP_JSON_T_DECREF json_t *tree = get_json_output (g, filename);
+ json_t *node;
if (tree == NULL)
return NULL;
- if (! YAJL_IS_OBJECT (tree))
+ if (!json_is_object (tree))
goto bad_type;
- len = YAJL_GET_OBJECT(tree)->len;
- for (i = 0; i < len; ++i) {
- if (STREQ (YAJL_GET_OBJECT(tree)->keys[i], "format")) {
- const char *str;
- yajl_val node = YAJL_GET_OBJECT(tree)->values[i];
- if (YAJL_IS_NULL (node))
- goto bad_type;
- str = YAJL_GET_STRING (node);
- if (str == NULL)
- goto bad_type;
- return safe_strdup (g, str); /* caller frees */
- }
- }
+ node = json_object_get (tree, "format");
+ if (!json_is_string (node))
+ goto bad_type;
+
+ return safe_strndup (g, json_string_value (node),
+ json_string_length (node)); /* caller frees */
bad_type:
error (g, _("qemu-img info: JSON output did not contain format key"));
@@ -93,30 +86,20 @@ guestfs_impl_disk_format (guestfs_h *g, const char *filename)
int64_t
guestfs_impl_disk_virtual_size (guestfs_h *g, const char *filename)
{
- size_t i, len;
- CLEANUP_YAJL_TREE_FREE yajl_val tree = get_json_output (g, filename);
+ CLEANUP_JSON_T_DECREF json_t *tree = get_json_output (g, filename);
+ json_t *node;
if (tree == NULL)
return -1;
- if (! YAJL_IS_OBJECT (tree))
+ if (!json_is_object (tree))
goto bad_type;
- len = YAJL_GET_OBJECT(tree)->len;
- for (i = 0; i < len; ++i) {
- if (STREQ (YAJL_GET_OBJECT(tree)->keys[i], "virtual-size")) {
- yajl_val node = YAJL_GET_OBJECT(tree)->values[i];
- if (YAJL_IS_NULL (node))
- goto bad_type;
- if (! YAJL_IS_NUMBER (node))
- goto bad_type;
- if (! YAJL_IS_INTEGER (node)) {
- error (g, _("qemu-img info: virtual-size is not representable as a 64 bit integer"));
- return -1;
- }
- return YAJL_GET_INTEGER (node);
- }
- }
+ node = json_object_get (tree, "virtual-size");
+ if (!json_is_integer (node))
+ goto bad_type;
+
+ return json_integer_value (node);
bad_type:
error (g, _("qemu-img info: JSON output did not contain virtual-size key"));
@@ -126,29 +109,25 @@ guestfs_impl_disk_virtual_size (guestfs_h *g, const char *filename)
int
guestfs_impl_disk_has_backing_file (guestfs_h *g, const char *filename)
{
- size_t i, len;
- CLEANUP_YAJL_TREE_FREE yajl_val tree = get_json_output (g, filename);
+ CLEANUP_JSON_T_DECREF json_t *tree = get_json_output (g, filename);
+ json_t *node;
if (tree == NULL)
return -1;
- if (! YAJL_IS_OBJECT (tree))
+ if (!json_is_object (tree))
goto bad_type;
- len = YAJL_GET_OBJECT(tree)->len;
- for (i = 0; i < len; ++i) {
- if (STREQ (YAJL_GET_OBJECT(tree)->keys[i], "backing-filename")) {
- yajl_val node = YAJL_GET_OBJECT(tree)->values[i];
- /* Work on the assumption that if this field is null, it means
- * no backing file, rather than being an error.
- */
- if (YAJL_IS_NULL (node))
- return 0;
- return 1;
- }
- }
+ node = json_object_get (tree, "backing-filename");
+ if (node == NULL)
+ return 0; /* no backing-filename key means no backing file */
- return 0; /* no backing-filename key means no backing file */
+ /* Work on the assumption that if this field is null, it means
+ * no backing file, rather than being an error.
+ */
+ if (json_is_null (node))
+ return 0;
+ return 1;
bad_type:
error (g, _("qemu-img info: JSON output was not an object"));
@@ -161,12 +140,12 @@ guestfs_impl_disk_has_backing_file (guestfs_h *g, const char *filename)
static void parse_json (guestfs_h *g, void *treevp, const char *input, size_t len);
#define PARSE_JSON_NO_OUTPUT ((void *) -1)
-static yajl_val
+static json_t *
get_json_output (guestfs_h *g, const char *filename)
{
CLEANUP_CMD_CLOSE struct command *cmd = guestfs_int_new_command (g);
int r;
- yajl_val tree = NULL;
+ json_t *tree = NULL;
guestfs_int_cmd_add_arg (cmd, "qemu-img");
guestfs_int_cmd_add_arg (cmd, "info");
@@ -196,16 +175,15 @@ get_json_output (guestfs_h *g, const char *filename)
return NULL;
}
- return tree; /* caller must call yajl_tree_free (tree) */
+ return tree; /* caller must call json_decref (tree) */
}
/* Parse the JSON document printed by qemu-img info --output json. */
static void
parse_json (guestfs_h *g, void *treevp, const char *input, size_t len)
{
- yajl_val *tree_ret = treevp;
- CLEANUP_FREE char *input_copy = NULL;
- char parse_error[256];
+ json_t **tree_ret = treevp;
+ json_error_t err;
assert (*tree_ret == NULL);
@@ -218,15 +196,12 @@ parse_json (guestfs_h *g, void *treevp, const char *input, size_t len)
return;
}
- /* 'input' is not \0-terminated; we have to make it so. */
- input_copy = safe_strndup (g, input, len);
-
- debug (g, "%s: qemu-img info JSON output:\n%s\n", __func__, input_copy);
+ debug (g, "%s: qemu-img info JSON output:\n%.*s\n", __func__, (int) len, input);
- *tree_ret = yajl_tree_parse (input_copy, parse_error, sizeof parse_error);
+ *tree_ret = json_loadb (input, len, 0, &err);
if (*tree_ret == NULL) {
- if (strlen (parse_error) > 0)
- error (g, _("qemu-img info: JSON parse error: %s"), parse_error);
+ if (strlen (err.text) > 0)
+ error (g, _("qemu-img info: JSON parse error: %s"), err.text);
else
error (g, _("qemu-img info: unknown JSON parse error"));
}
diff --git a/lib/qemu.c b/lib/qemu.c
index 6159b5a52..a50eca988 100644
--- a/lib/qemu.c
+++ b/lib/qemu.c
@@ -37,7 +37,7 @@
#include <libxml/uri.h>
-#include <yajl/yajl_tree.h>
+#include <jansson.h>
#include "full-write.h"
#include "ignore-value.h"
@@ -57,7 +57,7 @@ struct qemu_data {
/* The following fields are derived from the fields above. */
struct version qemu_version; /* Parsed qemu version number. */
- yajl_val qmp_schema_tree; /* qmp_schema parsed into a JSON tree */
+ json_t *qmp_schema_tree; /* qmp_schema parsed into a JSON tree */
};
static char *cache_filename (guestfs_h *g, const char *cachedir, const struct stat *, const char *suffix);
@@ -73,7 +73,7 @@ static int write_cache_qmp_schema (guestfs_h *g, const struct qemu_data *data, c
static int read_cache_qemu_stat (guestfs_h *g, struct qemu_data *data, const char *filename);
static int write_cache_qemu_stat (guestfs_h *g, const struct qemu_data *data, const char *filename);
static void parse_qemu_version (guestfs_h *g, const char *, struct version *qemu_version);
-static void parse_json (guestfs_h *g, const char *, yajl_val *);
+static void parse_json (guestfs_h *g, const char *, json_t **);
static void read_all (guestfs_h *g, void *retv, const char *buf, size_t len);
static int generic_read_cache (guestfs_h *g, const char *filename, char **strp);
static int generic_write_cache (guestfs_h *g, const char *filename, const char *str);
@@ -405,17 +405,17 @@ parse_qemu_version (guestfs_h *g, const char *qemu_help,
* is not possible.
*/
static void
-parse_json (guestfs_h *g, const char *json, yajl_val *treep)
+parse_json (guestfs_h *g, const char *json, json_t **treep)
{
- char parse_error[256] = "";
+ json_error_t err;
if (!json)
return;
- *treep = yajl_tree_parse (json, parse_error, sizeof parse_error);
+ *treep = json_loads (json, 0, &err);
if (*treep == NULL) {
- if (strlen (parse_error) > 0)
- debug (g, "QMP parse error: %s (ignored)", parse_error);
+ if (strlen (err.text) > 0)
+ debug (g, "QMP parse error: %s (ignored)", err.text);
else
debug (g, "QMP unknown parse error (ignored)");
}
@@ -580,17 +580,6 @@ guestfs_int_qemu_supports_device (guestfs_h *g,
return strstr (data->qemu_devices, device_name) != NULL;
}
-/* GCC can't work out that the YAJL_IS_<foo> test is sufficient to
- * ensure that YAJL_GET_<foo> later doesn't return NULL.
- */
-#pragma GCC diagnostic push
-#if defined(__GNUC__) && __GNUC__ >= 6 /* gcc >= 6 */
-#pragma GCC diagnostic ignored "-Wnull-dereference"
-#endif
-#if defined(__GNUC__) && GUESTFS_GCC_VERSION >= 40800 /* gcc >= 4.8.0 */
-#pragma GCC diagnostic ignored "-Wnonnull"
-#endif
-
/**
* Test if the qemu binary uses mandatory file locking, added in
* QEMU >= 2.10 (but sometimes disabled).
@@ -599,11 +588,7 @@ int
guestfs_int_qemu_mandatory_locking (guestfs_h *g,
const struct qemu_data *data)
{
- const char *return_path[] = { "return", NULL };
- const char *meta_type_path[] = { "meta-type", NULL };
- const char *members_path[] = { "members", NULL };
- const char *name_path[] = { "name", NULL };
- yajl_val schema, v, meta_type, members, m, name;
+ json_t *schema, *v, *meta_type, *members, *m, *name;
size_t i, j;
/* If there's no QMP schema, fall back to checking the version. */
@@ -616,27 +601,24 @@ guestfs_int_qemu_mandatory_locking (guestfs_h *g,
* Extract the schema from the wrapper. Note the returned schema
* will be an array.
*/
- schema = yajl_tree_get (data->qmp_schema_tree, return_path, yajl_t_array);
- if (schema == NULL)
+ schema = json_object_get (data->qmp_schema_tree, "return");
+ if (!json_is_array (schema))
goto fallback;
- assert (YAJL_IS_ARRAY(schema));
/* Now look for any member of the array which has:
* { "meta-type": "object",
* "members": [ ... { "name": "locking", ... } ... ] ... }
*/
- for (i = 0; i < YAJL_GET_ARRAY(schema)->len; ++i) {
- v = YAJL_GET_ARRAY(schema)->values[i];
- meta_type = yajl_tree_get (v, meta_type_path, yajl_t_string);
- if (meta_type && YAJL_IS_STRING (meta_type) &&
- STREQ (YAJL_GET_STRING (meta_type), "object")) {
- members = yajl_tree_get (v, members_path, yajl_t_array);
- if (members) {
- for (j = 0; j < YAJL_GET_ARRAY(members)->len; ++j) {
- m = YAJL_GET_ARRAY(members)->values[j];
- name = yajl_tree_get (m, name_path, yajl_t_string);
- if (name && YAJL_IS_STRING (name) &&
- STREQ (YAJL_GET_STRING (name), "locking"))
+ json_array_foreach (schema, i, v) {
+ meta_type = json_object_get (v, "meta-type");
+ if (json_is_string (meta_type) &&
+ STREQ (json_string_value (meta_type), "object")) {
+ members = json_object_get (v, "members");
+ if (json_is_array (members)) {
+ json_array_foreach (members, j, m) {
+ name = json_object_get (v, "name");
+ if (json_is_string (name) &&
+ STREQ (json_string_value (name), "locking"))
return 1;
}
}
@@ -646,8 +628,6 @@ guestfs_int_qemu_mandatory_locking (guestfs_h *g,
return 0;
}
-#pragma GCC diagnostic pop
-
/**
* Escape a qemu parameter.
*
@@ -996,7 +976,7 @@ guestfs_int_free_qemu_data (struct qemu_data *data)
free (data->qemu_help);
free (data->qemu_devices);
free (data->qmp_schema);
- yajl_tree_free (data->qmp_schema_tree);
+ json_decref (data->qmp_schema_tree);
free (data);
}
}
diff --git a/m4/guestfs-libraries.m4 b/m4/guestfs-libraries.m4
index 78a9e792f..2fdbd9669 100644
--- a/m4/guestfs-libraries.m4
+++ b/m4/guestfs-libraries.m4
@@ -299,8 +299,8 @@ LIBS="$LIBS $LIBXML2_LIBS"
AC_CHECK_FUNCS([xmlBufferDetach])
LIBS="$old_LIBS"
-dnl Check for yajl JSON library (required).
-PKG_CHECK_MODULES([YAJL], [yajl >= 2.0.4])
+dnl Check for Jansson JSON library (required).
+PKG_CHECK_MODULES([JANSSON], [jansson])
dnl Check for C++ (optional, we just use this to test the header works).
AC_PROG_CXX
--
2.21.0

View File

@ -0,0 +1,126 @@
From 6e0dbefde3ddb0711e2b0961ee913084dc5e6a41 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Tue, 19 Feb 2019 10:50:01 +0100
Subject: [PATCH] common/mlpcre: add offset flag for PCRE.matches
This way it is possible to change where the matching start, instead of
always assuming it is the beginning.
(cherry picked from commit 0ed2e5c14a302d15fd3b75ee2c1cb808a06cb746)
---
common/mlpcre/PCRE.ml | 2 +-
common/mlpcre/PCRE.mli | 5 ++++-
common/mlpcre/pcre-c.c | 16 +++++++++++++---
common/mlpcre/pcre_tests.ml | 11 ++++++++---
4 files changed, 26 insertions(+), 8 deletions(-)
diff --git a/common/mlpcre/PCRE.ml b/common/mlpcre/PCRE.ml
index b054928f9..33074af1c 100644
--- a/common/mlpcre/PCRE.ml
+++ b/common/mlpcre/PCRE.ml
@@ -23,7 +23,7 @@ exception Error of string * int
type regexp
external compile : ?anchored:bool -> ?caseless:bool -> ?dotall:bool -> ?extended:bool -> ?multiline:bool -> string -> regexp = "guestfs_int_pcre_compile_byte" "guestfs_int_pcre_compile"
-external matches : regexp -> string -> bool = "guestfs_int_pcre_matches"
+external matches : ?offset:int -> regexp -> string -> bool = "guestfs_int_pcre_matches"
external sub : int -> string = "guestfs_int_pcre_sub"
external subi : int -> int * int = "guestfs_int_pcre_subi"
diff --git a/common/mlpcre/PCRE.mli b/common/mlpcre/PCRE.mli
index eacb6fd90..e10d512fc 100644
--- a/common/mlpcre/PCRE.mli
+++ b/common/mlpcre/PCRE.mli
@@ -62,7 +62,7 @@ val compile : ?anchored:bool -> ?caseless:bool -> ?dotall:bool -> ?extended:bool
See pcreapi(3) for details of what they do.
All flags default to false. *)
-val matches : regexp -> string -> bool
+val matches : ?offset:int -> regexp -> string -> bool
(** Test whether the regular expression matches the string. This
returns true if the regexp matches or false otherwise.
@@ -71,6 +71,9 @@ val matches : regexp -> string -> bool
or the thread/program exits. You can call {!sub} to return
these substrings.
+ The [?offset] flag is used to change the start of the search,
+ which by default is at the beginning of the string (position 0).
+
This can raise {!Error} if PCRE returns an error. *)
val sub : int -> string
diff --git a/common/mlpcre/pcre-c.c b/common/mlpcre/pcre-c.c
index 0762a8341..be054a004 100644
--- a/common/mlpcre/pcre-c.c
+++ b/common/mlpcre/pcre-c.c
@@ -121,6 +121,15 @@ is_Some_true (value v)
Bool_val (Field (v, 0)) /* Some true */;
}
+static int
+Optint_val (value intv, int defval)
+{
+ if (intv == Val_int (0)) /* None */
+ return defval;
+ else /* Some int */
+ return Int_val (Field (intv, 0));
+}
+
value
guestfs_int_pcre_compile (value anchoredv, value caselessv, value dotallv,
value extendedv, value multilinev,
@@ -165,9 +174,9 @@ guestfs_int_pcre_compile_byte (value *argv, int argn)
}
value
-guestfs_int_pcre_matches (value rev, value strv)
+guestfs_int_pcre_matches (value offsetv, value rev, value strv)
{
- CAMLparam2 (rev, strv);
+ CAMLparam3 (offsetv, rev, strv);
pcre *re = Regexp_val (rev);
struct last_match *m, *oldm;
size_t len = caml_string_length (strv);
@@ -205,7 +214,8 @@ guestfs_int_pcre_matches (value rev, value strv)
caml_raise_out_of_memory ();
}
- m->r = pcre_exec (re, NULL, m->subject, len, 0, 0, m->vec, veclen);
+ m->r = pcre_exec (re, NULL, m->subject, len, Optint_val (offsetv, 0), 0,
+ m->vec, veclen);
if (m->r < 0 && m->r != PCRE_ERROR_NOMATCH) {
int ret = m->r;
free_last_match (m);
diff --git a/common/mlpcre/pcre_tests.ml b/common/mlpcre/pcre_tests.ml
index 346019c40..3e5981107 100644
--- a/common/mlpcre/pcre_tests.ml
+++ b/common/mlpcre/pcre_tests.ml
@@ -30,9 +30,9 @@ let compile ?(anchored = false) ?(caseless = false)
patt;
PCRE.compile ~anchored ~caseless ~dotall ~extended ~multiline patt
-let matches re str =
- eprintf "PCRE.matches %s ->%!" str;
- let r = PCRE.matches re str in
+let matches ?(offset = 0) re str =
+ eprintf "PCRE.matches %s, %d ->%!" str offset;
+ let r = PCRE.matches ~offset re str in
eprintf " %b\n%!" r;
r
@@ -103,6 +103,11 @@ let () =
assert (subi 1 = (2, 3));
assert (subi 2 = (3, 3));
+ assert (matches ~offset:5 re0 "aaabcabc" = true);
+ assert (sub 0 = "ab");
+
+ assert (matches ~offset:5 re0 "aaabcbaac" = false);
+
assert (replace re0 "dd" "abcabcaabccca" = "ddcabcaabccca");
assert (replace ~global:true re0 "dd" "abcabcaabccca" = "ddcddcddccca");
--
2.26.2

View File

@ -1,31 +0,0 @@
From 898e6c1e39deb130566220a11a2eaf2dcb2cb733 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Thu, 29 Mar 2018 20:18:34 +0100
Subject: [PATCH] qemu: Fix transcription error in conversion of yajl to
jansson.
This broke qemu mandatory locking detection.
Fixes commit bd1c5c9f4dcf38458099db8a0bf4659a07ef055d.
(cherry picked from commit e79286f71738d9385157d9e87211be02645722c3)
---
lib/qemu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/qemu.c b/lib/qemu.c
index a50eca988..3e7f15946 100644
--- a/lib/qemu.c
+++ b/lib/qemu.c
@@ -616,7 +616,7 @@ guestfs_int_qemu_mandatory_locking (guestfs_h *g,
members = json_object_get (v, "members");
if (json_is_array (members)) {
json_array_foreach (members, j, m) {
- name = json_object_get (v, "name");
+ name = json_object_get (m, "name");
if (json_is_string (name) &&
STREQ (json_string_value (name), "locking"))
return 1;
--
2.21.0

View File

@ -0,0 +1,415 @@
From a98136d6ee36df15a226f853d47bd803a7a25329 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Tue, 19 Feb 2019 14:54:31 +0100
Subject: [PATCH] v2v: add Var_expander
This helper module provides a facility to replace %{FOO}-like variables
in text strings with user-provided content.
(cherry picked from commit a27748d7000f417c16045967497208d275a09ce8)
---
.gitignore | 1 +
v2v/Makefile.am | 32 ++++++++++-
v2v/dummy.c | 2 +
v2v/var_expander.ml | 72 ++++++++++++++++++++++++
v2v/var_expander.mli | 82 +++++++++++++++++++++++++++
v2v/var_expander_tests.ml | 113 ++++++++++++++++++++++++++++++++++++++
6 files changed, 300 insertions(+), 2 deletions(-)
create mode 100644 v2v/dummy.c
create mode 100644 v2v/var_expander.ml
create mode 100644 v2v/var_expander.mli
create mode 100644 v2v/var_expander_tests.ml
diff --git a/.gitignore b/.gitignore
index 637bf7765..f2efcdde2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -693,6 +693,7 @@ Makefile.in
/v2v/uefi.ml
/v2v/uefi.mli
/v2v/v2v_unit_tests
+/v2v/var_expander_tests
/v2v/virt-v2v
/v2v/virt-v2v.1
/v2v/virt-v2v-copy-to-local
diff --git a/v2v/Makefile.am b/v2v/Makefile.am
index 2312812fb..f196be81d 100644
--- a/v2v/Makefile.am
+++ b/v2v/Makefile.am
@@ -98,6 +98,7 @@ SOURCES_MLI = \
utils.mli \
v2v.mli \
vCenter.mli \
+ var_expander.mli \
windows.mli \
windows_virtio.mli
@@ -106,6 +107,7 @@ SOURCES_ML = \
types.ml \
uefi.ml \
utils.ml \
+ var_expander.ml \
python_script.ml \
name_from_disk.ml \
vCenter.ml \
@@ -442,7 +444,7 @@ TESTS += \
endif
if HAVE_OCAML_PKG_OUNIT
-TESTS += v2v_unit_tests
+TESTS += v2v_unit_tests var_expander_tests
endif
if ENABLE_APPLIANCE
@@ -651,7 +653,7 @@ EXTRA_DIST += \
# Unit tests.
check_PROGRAMS =
if HAVE_OCAML_PKG_OUNIT
-check_PROGRAMS += v2v_unit_tests
+check_PROGRAMS += v2v_unit_tests var_expander_tests
endif
v2v_unit_tests_BOBJECTS = \
@@ -671,13 +673,28 @@ v2v_unit_tests_SOURCES = $(virt_v2v_SOURCES)
v2v_unit_tests_CPPFLAGS = $(virt_v2v_CPPFLAGS)
v2v_unit_tests_CFLAGS = $(virt_v2v_CFLAGS)
+var_expander_tests_BOBJECTS = \
+ var_expander.cmo \
+ var_expander_tests.cmo
+var_expander_tests_XOBJECTS = $(var_expander_tests_BOBJECTS:.cmo=.cmx)
+
+var_expander_tests_SOURCES = dummy.c
+var_expander_tests_CPPFLAGS = $(virt_v2v_CPPFLAGS)
+var_expander_tests_CFLAGS = $(virt_v2v_CFLAGS)
+
if !HAVE_OCAMLOPT
# Can't call this v2v_unit_tests_OBJECTS because automake gets confused.
v2v_unit_tests_THEOBJECTS = $(v2v_unit_tests_BOBJECTS)
v2v_unit_tests.cmo: OCAMLPACKAGES += -package oUnit
+
+var_expander_tests_THEOBJECTS = $(var_expander_tests_BOBJECTS)
+var_expander_tests.cmo: OCAMLPACKAGES += -package oUnit
else
v2v_unit_tests_THEOBJECTS = $(v2v_unit_tests_XOBJECTS)
v2v_unit_tests.cmx: OCAMLPACKAGES += -package oUnit
+
+var_expander_tests_THEOBJECTS = $(var_expander_tests_XOBJECTS)
+var_expander_tests.cmx: OCAMLPACKAGES += -package oUnit
endif
v2v_unit_tests_DEPENDENCIES = \
@@ -696,6 +713,17 @@ v2v_unit_tests_LINK = \
$(OCAMLLINKFLAGS) \
$(v2v_unit_tests_THEOBJECTS) -o $@
+var_expander_tests_DEPENDENCIES = \
+ $(var_expander_tests_THEOBJECTS) \
+ ../common/mlpcre/mlpcre.$(MLARCHIVE) \
+ $(top_srcdir)/ocaml-link.sh
+var_expander_tests_LINK = \
+ $(top_srcdir)/ocaml-link.sh -cclib '$(OCAMLCLIBS)' -- \
+ $(OCAMLFIND) $(BEST) $(OCAMLFLAGS) \
+ $(OCAMLPACKAGES) -package oUnit \
+ $(OCAMLLINKFLAGS) \
+ $(var_expander_tests_THEOBJECTS) -o $@
+
# Dependencies.
.depend: \
$(srcdir)/*.mli \
diff --git a/v2v/dummy.c b/v2v/dummy.c
new file mode 100644
index 000000000..ebab6198c
--- /dev/null
+++ b/v2v/dummy.c
@@ -0,0 +1,2 @@
+/* Dummy source, to be used for OCaml-based tools with no C sources. */
+enum { foo = 1 };
diff --git a/v2v/var_expander.ml b/v2v/var_expander.ml
new file mode 100644
index 000000000..24b9bafe3
--- /dev/null
+++ b/v2v/var_expander.ml
@@ -0,0 +1,72 @@
+(* virt-v2v
+ * Copyright (C) 2019 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+open Std_utils
+
+exception Invalid_variable of string
+
+let var_re = PCRE.compile "(^|[^%])%{([^}]+)}"
+
+let check_variable var =
+ String.iter (
+ function
+ | '0'..'9'
+ | 'a'..'z'
+ | 'A'..'Z'
+ | '_'
+ | '-' -> ()
+ | _ -> raise (Invalid_variable var)
+ ) var
+
+let scan_variables str =
+ let res = ref [] in
+ let offset = ref 0 in
+ while PCRE.matches ~offset:!offset var_re str; do
+ let var = PCRE.sub 2 in
+ check_variable var;
+ let _, end_ = PCRE.subi 0 in
+ List.push_back res var;
+ offset := end_
+ done;
+ List.remove_duplicates !res
+
+let replace_fn str fn =
+ let res = ref str in
+ let offset = ref 0 in
+ while PCRE.matches ~offset:!offset var_re !res; do
+ let var = PCRE.sub 2 in
+ check_variable var;
+ let start_, end_ = PCRE.subi 0 in
+ match fn var with
+ | None ->
+ offset := end_
+ | Some text ->
+ let prefix_len =
+ let prefix_start, prefix_end = PCRE.subi 1 in
+ prefix_end - prefix_start in
+ res := (String.sub !res 0 (start_ + prefix_len)) ^ text ^ (String.sub !res end_ (String.length !res - end_));
+ offset := start_ + prefix_len + String.length text
+ done;
+ !res
+
+let replace_list str lst =
+ let fn var =
+ try Some (List.assoc var lst)
+ with Not_found -> None
+ in
+ replace_fn str fn
diff --git a/v2v/var_expander.mli b/v2v/var_expander.mli
new file mode 100644
index 000000000..80aa33c2c
--- /dev/null
+++ b/v2v/var_expander.mli
@@ -0,0 +1,82 @@
+(* virt-v2v
+ * Copyright (C) 2019 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+(** Simple variable expander.
+
+ This module provides the support to expand variables in strings,
+ specified in the form of [%{name}].
+
+ For example:
+
+{v
+let str = "variable-%{INDEX} in %{INDEX} replaced %{INDEX} times"
+let index = ref 0
+let fn = function
+ | "INDEX" ->
+ incr index;
+ Some (string_of_int !index)
+ | _ -> None
+in
+let str = Var_expander.replace_fn str fn
+(* now str is "variable-1 in 2 replaced 3 times" *)
+v}
+
+ The names of variables can contain only ASCII letters (uppercase,
+ and lowercase), digits, underscores, and dashes.
+
+ The replacement is done in a single pass: this means that if a
+ variable is replaced with the text of a variable, that new text
+ is kept as is in the final output. In practice:
+
+{v
+let str = "%{VAR}"
+let str = Var_expander.replace_list str [("VAR", "%{VAR}")]
+(* now str is "%{VAR}" *)
+v}
+*)
+
+exception Invalid_variable of string
+(** Invalid variable name error.
+
+ In case a variable contains characters not allowed, then this
+ exception with the actual unacceptable variable. *)
+
+val scan_variables : string -> string list
+(** Scan the pattern string for all the variables available.
+
+ This can raise {!Invalid_variable} in case there are invalid
+ variable names. *)
+
+val replace_fn : string -> (string -> string option) -> string
+(** Replaces a string expanding all the variables.
+
+ The replacement function specify how a variable is replaced;
+ if [None] is returned, then that variable is not replaced.
+
+ This can raise {!Invalid_variable} in case there are invalid
+ variable names. *)
+
+val replace_list : string -> (string * string) list -> string
+(** Replaces a string expanding all the variables.
+
+ The replacement list specify how a variable is replaced;
+ if it is not specified in the list, then that variable is not
+ replaced.
+
+ This can raise {!Invalid_variable} in case there are invalid
+ variable names. *)
diff --git a/v2v/var_expander_tests.ml b/v2v/var_expander_tests.ml
new file mode 100644
index 000000000..35b628369
--- /dev/null
+++ b/v2v/var_expander_tests.ml
@@ -0,0 +1,113 @@
+(* virt-v2v
+ * Copyright (C) 2019 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+open Printf
+open OUnit
+
+open Std_utils
+
+let assert_equal_string = assert_equal ~printer:identity
+let assert_equal_stringlist = assert_equal ~printer:(fun x -> "(" ^ (String.escaped (String.concat "," x)) ^ ")")
+
+let replace_none_fn _ = None
+let replace_empty_fn _ = Some ""
+
+let test_no_replacement () =
+ assert_equal_string "" (Var_expander.replace_fn "" replace_none_fn);
+ assert_equal_string "x" (Var_expander.replace_fn "x" replace_none_fn);
+ assert_equal_string "%{}" (Var_expander.replace_fn "%{}" replace_none_fn);
+ assert_equal_string "%{EMPTY}" (Var_expander.replace_fn "%{EMPTY}" replace_none_fn);
+ assert_equal_string "%{EMPTY} %{no}" (Var_expander.replace_fn "%{EMPTY} %{no}" replace_none_fn);
+ assert_equal_string "a %{EMPTY} b" (Var_expander.replace_fn "a %{EMPTY} b" replace_none_fn);
+ ()
+
+let test_replacements () =
+ assert_equal_string "" (Var_expander.replace_fn "%{EMPTY}" replace_empty_fn);
+ assert_equal_string "x " (Var_expander.replace_fn "x %{EMPTY}" replace_empty_fn);
+ assert_equal_string "xy" (Var_expander.replace_fn "x%{EMPTY}y" replace_empty_fn);
+ assert_equal_string "x<->y" (Var_expander.replace_fn "x%{FOO}y" (function | "FOO" -> Some "<->" | _ -> None));
+ assert_equal_string "a x b" (Var_expander.replace_fn "a %{FOO} b" (function | "FOO" -> Some "x" | _ -> None));
+ assert_equal_string "%{FOO} x" (Var_expander.replace_fn "%{FOO} %{BAR}" (function | "BAR" -> Some "x" | _ -> None));
+ assert_equal_string "%{FOO}" (Var_expander.replace_fn "%{BAR}" (function | "BAR" -> Some "%{FOO}" | _ -> None));
+ assert_equal_string "%{FOO} x" (Var_expander.replace_fn "%{BAR} %{FOO}" (function | "BAR" -> Some "%{FOO}" | "FOO" -> Some "x" | _ -> None));
+ begin
+ let str = "%{INDEX}, %{INDEX}, %{INDEX}" in
+ let index = ref 0 in
+ let fn = function
+ | "INDEX" ->
+ incr index;
+ Some (string_of_int !index)
+ | _ -> None
+ in
+ assert_equal_string "1, 2, 3" (Var_expander.replace_fn str fn)
+ end;
+ ()
+
+let test_escape () =
+ assert_equal_string "%%{FOO}" (Var_expander.replace_fn "%%{FOO}" replace_empty_fn);
+ assert_equal_string "x %%{FOO} x" (Var_expander.replace_fn "%{FOO} %%{FOO} %{FOO}" (function | "FOO" -> Some "x" | _ -> None));
+ ()
+
+let test_list () =
+ assert_equal_string "x %{NONE}" (Var_expander.replace_list "%{FOO} %{NONE}" [("FOO", "x")]);
+ ()
+
+let test_scan_variables () =
+ let assert_invalid_variable var =
+ let str = "%{" ^ var ^ "}" in
+ assert_raises (Var_expander.Invalid_variable var)
+ (fun () -> Var_expander.scan_variables str)
+ in
+ assert_equal_stringlist [] (Var_expander.scan_variables "");
+ assert_equal_stringlist [] (Var_expander.scan_variables "foo");
+ assert_equal_stringlist ["FOO"] (Var_expander.scan_variables "%{FOO}");
+ assert_equal_stringlist ["FOO"; "BAR"] (Var_expander.scan_variables "%{FOO} %{BAR}");
+ assert_equal_stringlist ["FOO"; "BAR"] (Var_expander.scan_variables "%{FOO} %{BAR} %{FOO}");
+ assert_equal_stringlist ["FOO"; "BAR"] (Var_expander.scan_variables "%{FOO} %%{ESCAPED} %{BAR}");
+ assert_invalid_variable "FOO/BAR";
+ ()
+
+let test_errors () =
+ let assert_invalid_variable var =
+ let str = "%{" ^ var ^ "}" in
+ assert_raises (Var_expander.Invalid_variable var)
+ (fun () -> Var_expander.replace_fn str replace_none_fn)
+ in
+ assert_invalid_variable "FOO/BAR";
+ assert_invalid_variable "FOO:BAR";
+ assert_invalid_variable "FOO(BAR";
+ assert_invalid_variable "FOO)BAR";
+ assert_invalid_variable "FOO@BAR";
+ ()
+
+(* Suites declaration. *)
+let suite =
+ TestList ([
+ "basic" >::: [
+ "no_replacement" >:: test_no_replacement;
+ "replacements" >:: test_replacements;
+ "escape" >:: test_escape;
+ "list" >:: test_list;
+ "scan_variables" >:: test_scan_variables;
+ "errors" >:: test_errors;
+ ];
+ ])
+
+let () =
+ ignore (run_test_tt_main suite);
+ Printf.fprintf stderr "\n"
--
2.26.2

View File

@ -0,0 +1,785 @@
From 480c7169c341fc2f86609a13100c42e10f599b83 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Mon, 25 Feb 2019 13:14:43 +0100
Subject: [PATCH] v2v: add -o json output mode
Add a new output mode to virt-v2v: similar to -o local, the written
metadata is a JSON file with the majority of the data that virt-v2v
knowns about (or collects) during the conversion.
This is meant to be used only when no existing output mode is usable,
and a guest needs to be converted to run on KVM anyway. The user of
this mode is supposed to use all the data in the JSON, as they contain
important details on how even run the guest (e.g. w.r.t. firmware,
drivers of disks/NICs, etc).
(cherry picked from commit f190e08d85556dac293ef15bfeee38e54471570f)
---
v2v/Makefile.am | 4 +
v2v/cmdline.ml | 29 +++
v2v/create_json.ml | 348 ++++++++++++++++++++++++++++++++++
v2v/create_json.mli | 29 +++
v2v/output_json.ml | 116 ++++++++++++
v2v/output_json.mli | 31 +++
v2v/virt-v2v-output-local.pod | 55 ++++++
v2v/virt-v2v.pod | 15 +-
8 files changed, 625 insertions(+), 2 deletions(-)
create mode 100644 v2v/create_json.ml
create mode 100644 v2v/create_json.mli
create mode 100644 v2v/output_json.ml
create mode 100644 v2v/output_json.mli
diff --git a/v2v/Makefile.am b/v2v/Makefile.am
index f196be81d..53c137fc6 100644
--- a/v2v/Makefile.am
+++ b/v2v/Makefile.am
@@ -52,6 +52,7 @@ SOURCES_MLI = \
config.mli \
convert_linux.mli \
convert_windows.mli \
+ create_json.mli \
create_libvirt_xml.mli \
create_ovf.mli \
DOM.mli \
@@ -75,6 +76,7 @@ SOURCES_MLI = \
networks.mli \
openstack_image_properties.mli \
output_glance.mli \
+ output_json.mli \
output_libvirt.mli \
output_local.mli \
output_null.mli \
@@ -117,6 +119,7 @@ SOURCES_ML = \
parse_ovf_from_ova.ml \
parse_ova.ml \
create_ovf.ml \
+ create_json.ml \
linux.ml \
windows.ml \
windows_virtio.ml \
@@ -141,6 +144,7 @@ SOURCES_ML = \
convert_windows.ml \
output_null.ml \
output_glance.ml \
+ output_json.ml \
output_libvirt.ml \
output_local.ml \
output_qemu.ml \
diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
index 46f6910d0..4d390f249 100644
--- a/v2v/cmdline.ml
+++ b/v2v/cmdline.ml
@@ -138,6 +138,7 @@ let parse_cmdline () =
| "glance" -> output_mode := `Glance
| "libvirt" -> output_mode := `Libvirt
| "disk" | "local" -> output_mode := `Local
+ | "json" -> output_mode := `JSON
| "null" -> output_mode := `Null
| "openstack" | "osp" | "rhosp" -> output_mode := `Openstack
| "ovirt" | "rhv" | "rhev" -> output_mode := `RHV
@@ -413,6 +414,17 @@ read the man page virt-v2v(1).
| `RHV -> no_options (); `RHV
| `QEmu -> no_options (); `QEmu
+ | `JSON ->
+ if is_query then (
+ Output_json.print_output_options ();
+ exit 0
+ )
+ else (
+ let json_options =
+ Output_json.parse_output_options output_options in
+ `JSON json_options
+ )
+
| `Openstack ->
if is_query then (
Output_openstack.print_output_options ();
@@ -546,6 +558,23 @@ read the man page virt-v2v(1).
Output_libvirt.output_libvirt output_conn output_storage,
output_format, output_alloc
+ | `JSON json_options ->
+ if output_password <> None then
+ error_option_cannot_be_used_in_output_mode "json" "-op";
+ if output_conn <> None then
+ error_option_cannot_be_used_in_output_mode "json" "-oc";
+ let os =
+ match output_storage with
+ | None ->
+ error (f_"-o json: output directory was not specified, use '-os /dir'")
+ | Some d when not (is_directory d) ->
+ error (f_"-os %s: output directory does not exist or is not a directory") d
+ | Some d -> d in
+ if qemu_boot then
+ error_option_cannot_be_used_in_output_mode "json" "--qemu-boot";
+ Output_json.output_json os json_options,
+ output_format, output_alloc
+
| `Local ->
if output_password <> None then
error_option_cannot_be_used_in_output_mode "local" "-op";
diff --git a/v2v/create_json.ml b/v2v/create_json.ml
new file mode 100644
index 000000000..fdf7b12f5
--- /dev/null
+++ b/v2v/create_json.ml
@@ -0,0 +1,348 @@
+(* virt-v2v
+ * Copyright (C) 2019 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+open Std_utils
+open C_utils
+open Tools_utils
+
+open Types
+open Utils
+
+module G = Guestfs
+
+let json_list_of_string_list =
+ List.map (fun x -> JSON.String x)
+
+let json_list_of_string_string_list =
+ List.map (fun (x, y) -> x, JSON.String y)
+
+let push_optional_string lst name = function
+ | None -> ()
+ | Some v -> List.push_back lst (name, JSON.String v)
+
+let push_optional_int lst name = function
+ | None -> ()
+ | Some v -> List.push_back lst (name, JSON.Int (Int64.of_int v))
+
+let json_unknown_string = function
+ | "unknown" -> JSON.Null
+ | v -> JSON.String v
+
+let find_target_disk targets { s_disk_id = id } =
+ try List.find (fun t -> t.target_overlay.ov_source.s_disk_id = id) targets
+ with Not_found -> assert false
+
+let create_json_metadata source targets target_buses
+ guestcaps inspect target_firmware =
+ let doc = ref [
+ "version", JSON.Int 1L;
+ "name", JSON.String source.s_name;
+ "memory", JSON.Int source.s_memory;
+ "vcpu", JSON.Int (Int64.of_int source.s_vcpu);
+ ] in
+
+ (match source.s_genid with
+ | None -> ()
+ | Some genid -> List.push_back doc ("genid", JSON.String genid)
+ );
+
+ if source.s_cpu_vendor <> None || source.s_cpu_model <> None ||
+ source.s_cpu_topology <> None then (
+ let cpu = ref [] in
+
+ push_optional_string cpu "vendor" source.s_cpu_vendor;
+ push_optional_string cpu "model" source.s_cpu_model;
+ (match source.s_cpu_topology with
+ | None -> ()
+ | Some { s_cpu_sockets; s_cpu_cores; s_cpu_threads } ->
+ let attrs = [
+ "sockets", JSON.Int (Int64.of_int s_cpu_sockets);
+ "cores", JSON.Int (Int64.of_int s_cpu_cores);
+ "threads", JSON.Int (Int64.of_int s_cpu_threads);
+ ] in
+ List.push_back cpu ("topology", JSON.Dict attrs)
+ );
+
+ List.push_back doc ("cpu", JSON.Dict !cpu);
+ );
+
+ let firmware =
+ let firmware_type =
+ match target_firmware with
+ | TargetBIOS -> "bios"
+ | TargetUEFI -> "uefi" in
+
+ let fw = ref [
+ "type", JSON.String firmware_type;
+ ] in
+
+ (match target_firmware with
+ | TargetBIOS -> ()
+ | TargetUEFI ->
+ let uefi_firmware = find_uefi_firmware guestcaps.gcaps_arch in
+ let flags =
+ List.map (
+ function
+ | Uefi.UEFI_FLAG_SECURE_BOOT_REQUIRED -> "secure_boot_required"
+ ) uefi_firmware.Uefi.flags in
+
+ let uefi = ref [
+ "code", JSON.String uefi_firmware.Uefi.code;
+ "vars", JSON.String uefi_firmware.Uefi.vars;
+ "flags", JSON.List (json_list_of_string_list flags);
+ ] in
+
+ push_optional_string uefi "code-debug" uefi_firmware.Uefi.code_debug;
+
+ List.push_back fw ("uefi", JSON.Dict !uefi)
+ );
+
+ !fw in
+ List.push_back doc ("firmware", JSON.Dict firmware);
+
+ List.push_back doc ("features",
+ JSON.List (json_list_of_string_list source.s_features));
+
+ let machine =
+ match guestcaps.gcaps_machine with
+ | I440FX -> "pc"
+ | Q35 -> "q35"
+ | Virt -> "virt" in
+ List.push_back doc ("machine", JSON.String machine);
+
+ let disks, removables =
+ let disks = ref []
+ and removables = ref [] in
+
+ let iter_bus bus_name drive_prefix i = function
+ | BusSlotEmpty -> ()
+ | BusSlotDisk d ->
+ (* Find the corresponding target disk. *)
+ let t = find_target_disk targets d in
+
+ let target_file =
+ match t.target_file with
+ | TargetFile s -> s
+ | TargetURI _ -> assert false in
+
+ let disk = [
+ "dev", JSON.String (drive_prefix ^ drive_name i);
+ "bus", JSON.String bus_name;
+ "format", JSON.String t.target_format;
+ "file", JSON.String (absolute_path target_file);
+ ] in
+
+ List.push_back disks (JSON.Dict disk)
+
+ | BusSlotRemovable { s_removable_type = CDROM } ->
+ let cdrom = [
+ "type", JSON.String "cdrom";
+ "dev", JSON.String (drive_prefix ^ drive_name i);
+ "bus", JSON.String bus_name;
+ ] in
+
+ List.push_back removables (JSON.Dict cdrom)
+
+ | BusSlotRemovable { s_removable_type = Floppy } ->
+ let floppy = [
+ "type", JSON.String "floppy";
+ "dev", JSON.String (drive_prefix ^ drive_name i);
+ ] in
+
+ List.push_back removables (JSON.Dict floppy)
+ in
+
+ Array.iteri (iter_bus "virtio" "vd") target_buses.target_virtio_blk_bus;
+ Array.iteri (iter_bus "ide" "hd") target_buses.target_ide_bus;
+ Array.iteri (iter_bus "scsi" "sd") target_buses.target_scsi_bus;
+ Array.iteri (iter_bus "floppy" "fd") target_buses.target_floppy_bus;
+
+ !disks, !removables in
+ List.push_back doc ("disks", JSON.List disks);
+ List.push_back doc ("removables", JSON.List removables);
+
+ let nics =
+ List.map (
+ fun { s_mac = mac; s_vnet_type = vnet_type; s_nic_model = nic_model;
+ s_vnet = vnet; } ->
+ let vnet_type_str =
+ match vnet_type with
+ | Bridge -> "bridge"
+ | Network -> "network" in
+
+ let nic = ref [
+ "vnet", JSON.String vnet;
+ "vnet-type", JSON.String vnet_type_str;
+ ] in
+
+ let nic_model_str = Option.map string_of_nic_model nic_model in
+ push_optional_string nic "model" nic_model_str;
+
+ push_optional_string nic "mac" mac;
+
+ JSON.Dict !nic
+ ) source.s_nics in
+ List.push_back doc ("nics", JSON.List nics);
+
+ let guestcaps_dict =
+ let block_bus =
+ match guestcaps.gcaps_block_bus with
+ | Virtio_blk -> "virtio-blk"
+ | Virtio_SCSI -> "virtio-scsi"
+ | IDE -> "ide" in
+ let net_bus =
+ match guestcaps.gcaps_net_bus with
+ | Virtio_net -> "virtio-net"
+ | E1000 -> "e1000"
+ | RTL8139 -> "rtl8139" in
+ let video =
+ match guestcaps.gcaps_video with
+ | QXL -> "qxl"
+ | Cirrus -> "cirrus" in
+ let machine =
+ match guestcaps.gcaps_machine with
+ | I440FX -> "i440fx"
+ | Q35 -> "q35"
+ | Virt -> "virt" in
+
+ [
+ "block-bus", JSON.String block_bus;
+ "net-bus", JSON.String net_bus;
+ "video", JSON.String video;
+ "machine", JSON.String machine;
+ "arch", JSON.String guestcaps.gcaps_arch;
+ "virtio-rng", JSON.Bool guestcaps.gcaps_virtio_rng;
+ "virtio-balloon", JSON.Bool guestcaps.gcaps_virtio_balloon;
+ "isa-pvpanic", JSON.Bool guestcaps.gcaps_isa_pvpanic;
+ "acpi", JSON.Bool guestcaps.gcaps_acpi;
+ ] in
+ List.push_back doc ("guestcaps", JSON.Dict guestcaps_dict);
+
+ (match source.s_sound with
+ | None -> ()
+ | Some { s_sound_model = model } ->
+ let sound = [
+ "model", JSON.String (string_of_source_sound_model model);
+ ] in
+ List.push_back doc ("sound", JSON.Dict sound)
+ );
+
+ (match source.s_display with
+ | None -> ()
+ | Some d ->
+ let display_type =
+ match d.s_display_type with
+ | Window -> "window"
+ | VNC -> "vnc"
+ | Spice -> "spice" in
+
+ let display = ref [
+ "type", JSON.String display_type;
+ ] in
+
+ push_optional_string display "keymap" d.s_keymap;
+ push_optional_string display "password" d.s_password;
+
+ let listen =
+ match d.s_listen with
+ | LNoListen -> None
+ | LAddress address ->
+ Some [
+ "type", JSON.String "address";
+ "address", JSON.String address;
+ ]
+ | LNetwork network ->
+ Some [
+ "type", JSON.String "network";
+ "network", JSON.String network;
+ ]
+ | LSocket None ->
+ Some [
+ "type", JSON.String "socket";
+ "socket", JSON.Null;
+ ]
+ | LSocket (Some socket) ->
+ Some [
+ "type", JSON.String "socket";
+ "socket", JSON.String socket;
+ ]
+ | LNone ->
+ Some [
+ "type", JSON.String "none";
+ ] in
+ (match listen with
+ | None -> ()
+ | Some l -> List.push_back display ("listen", JSON.Dict l)
+ );
+
+ push_optional_int display "port" d.s_port;
+
+ List.push_back doc ("display", JSON.Dict !display)
+ );
+
+ let inspect_dict =
+ let apps =
+ List.map (
+ fun { G.app2_name = name; app2_display_name = display_name;
+ app2_epoch = epoch; app2_version = version;
+ app2_release = release; app2_arch = arch; } ->
+ JSON.Dict [
+ "name", JSON.String name;
+ "display-name", JSON.String display_name;
+ "epoch", JSON.Int (Int64.of_int32 epoch);
+ "version", JSON.String version;
+ "release", JSON.String release;
+ "arch", JSON.String arch;
+ ]
+ ) inspect.i_apps in
+
+ let firmware_dict =
+ match inspect.i_firmware with
+ | I_BIOS ->
+ [
+ "type", JSON.String "bios";
+ ]
+ | I_UEFI devices ->
+ [
+ "type", JSON.String "uefi";
+ "devices", JSON.List (json_list_of_string_list devices);
+ ] in
+
+ [
+ "root", JSON.String inspect.i_root;
+ "type", JSON.String inspect.i_type;
+ "distro", json_unknown_string inspect.i_distro;
+ "osinfo", json_unknown_string inspect.i_osinfo;
+ "arch", JSON.String inspect.i_arch;
+ "major-version", JSON.Int (Int64.of_int inspect.i_major_version);
+ "minor-version", JSON.Int (Int64.of_int inspect.i_minor_version);
+ "package-format", json_unknown_string inspect.i_package_format;
+ "package-management", json_unknown_string inspect.i_package_management;
+ "product-name", json_unknown_string inspect.i_product_name;
+ "product-variant", json_unknown_string inspect.i_product_variant;
+ "mountpoints", JSON.Dict (json_list_of_string_string_list inspect.i_mountpoints);
+ "applications", JSON.List apps;
+ "windows-systemroot", JSON.String inspect.i_windows_systemroot;
+ "windows-software-hive", JSON.String inspect.i_windows_software_hive;
+ "windows-system-hive", JSON.String inspect.i_windows_system_hive;
+ "windows-current-control-set", JSON.String inspect.i_windows_current_control_set;
+ "firmware", JSON.Dict firmware_dict;
+ ] in
+ List.push_back doc ("inspect", JSON.Dict inspect_dict);
+
+ !doc
diff --git a/v2v/create_json.mli b/v2v/create_json.mli
new file mode 100644
index 000000000..6dbb6e48b
--- /dev/null
+++ b/v2v/create_json.mli
@@ -0,0 +1,29 @@
+(* virt-v2v
+ * Copyright (C) 2019 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+(** Create JSON metadata for [-o json]. *)
+
+val create_json_metadata : Types.source -> Types.target list ->
+ Types.target_buses ->
+ Types.guestcaps ->
+ Types.inspect ->
+ Types.target_firmware ->
+ JSON.doc
+(** [create_json_metadata source targets target_buses guestcaps
+ inspect target_firmware] creates the JSON with the majority
+ of the data that virt-v2v used for the conversion. *)
diff --git a/v2v/output_json.ml b/v2v/output_json.ml
new file mode 100644
index 000000000..ca0bda978
--- /dev/null
+++ b/v2v/output_json.ml
@@ -0,0 +1,116 @@
+(* virt-v2v
+ * Copyright (C) 2019 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+open Printf
+
+open Std_utils
+open Tools_utils
+open Common_gettext.Gettext
+
+open Types
+open Utils
+
+type json_options = {
+ json_disks_pattern : string;
+}
+
+let print_output_options () =
+ printf (f_"Output options (-oo) which can be used with -o json:
+
+ -oo json-disks-pattern=PATTERN Pattern for the disks.
+")
+
+let known_pattern_variables = ["DiskNo"; "DiskDeviceName"; "GuestName"]
+
+let parse_output_options options =
+ let json_disks_pattern = ref None in
+
+ List.iter (
+ function
+ | "json-disks-pattern", v ->
+ if !json_disks_pattern <> None then
+ error (f_"-o json: -oo json-disks-pattern set more than once");
+ let vars =
+ try Var_expander.scan_variables v
+ with Var_expander.Invalid_variable var ->
+ error (f_"-o json: -oo json-disks-pattern: invalid variable %%{%s}")
+ var in
+ List.iter (
+ fun var ->
+ if not (List.mem var known_pattern_variables) then
+ error (f_"-o json: -oo json-disks-pattern: unhandled variable %%{%s}")
+ var
+ ) vars;
+ json_disks_pattern := Some v
+ | k, _ ->
+ error (f_"-o json: unknown output option -oo %s") k
+ ) options;
+
+ let json_disks_pattern =
+ Option.default "%{GuestName}-%{DiskDeviceName}" !json_disks_pattern in
+
+ { json_disks_pattern }
+
+class output_json dir json_options = object
+ inherit output
+
+ method as_options = sprintf "-o json -os %s" dir
+
+ method prepare_targets source overlays _ _ _ _ =
+ List.mapi (
+ fun i (_, ov) ->
+ let outname =
+ let vars_fn = function
+ | "DiskNo" -> Some (string_of_int (i+1))
+ | "DiskDeviceName" -> Some ov.ov_sd
+ | "GuestName" -> Some source.s_name
+ | _ -> assert false
+ in
+ Var_expander.replace_fn json_options.json_disks_pattern vars_fn in
+ let destname = dir // outname in
+ mkdir_p (Filename.dirname destname) 0o755;
+ TargetFile destname
+ ) overlays
+
+ method supported_firmware = [ TargetBIOS; TargetUEFI ]
+
+ method create_metadata source targets
+ target_buses guestcaps inspect target_firmware =
+ let doc =
+ Create_json.create_json_metadata source targets target_buses
+ guestcaps inspect target_firmware in
+ let doc_string = JSON.string_of_doc ~fmt:JSON.Indented doc in
+
+ if verbose () then (
+ eprintf "resulting JSON:\n";
+ output_string stderr doc_string;
+ eprintf "\n\n%!";
+ );
+
+ let name = source.s_name in
+ let file = dir // name ^ ".json" in
+
+ with_open_out file (
+ fun chan ->
+ output_string chan doc_string;
+ output_char chan '\n'
+ )
+end
+
+let output_json = new output_json
+let () = Modules_list.register_output_module "json"
diff --git a/v2v/output_json.mli b/v2v/output_json.mli
new file mode 100644
index 000000000..52f58f2d1
--- /dev/null
+++ b/v2v/output_json.mli
@@ -0,0 +1,31 @@
+(* virt-v2v
+ * Copyright (C) 2019 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+(** [-o json] target. *)
+
+type json_options
+(** Miscellaneous extra command line parameters used by json. *)
+
+val print_output_options : unit -> unit
+val parse_output_options : (string * string) list -> json_options
+(** Print and parse json -oo options. *)
+
+val output_json : string -> json_options -> Types.output
+(** [output_json directory json_options] creates and returns a new
+ {!Types.output} object specialized for writing output to local
+ files with JSON metadata. *)
diff --git a/v2v/virt-v2v-output-local.pod b/v2v/virt-v2v-output-local.pod
index 7427b1ed7..7c397c0a4 100644
--- a/v2v/virt-v2v-output-local.pod
+++ b/v2v/virt-v2v-output-local.pod
@@ -11,6 +11,9 @@ or libvirt
virt-v2v [-i* options] -o qemu -os DIRECTORY [--qemu-boot]
+ virt-v2v [-i* options] -o json -os DIRECTORY
+ [-oo json-disks-pattern=PATTERN]
+
virt-v2v [-i* options] -o null
=head1 DESCRIPTION
@@ -54,6 +57,13 @@ above, a shell script is created which contains the raw qemu command
you would need to boot the guest. However the shell script is not
run, I<unless> you also add the I<--qemu-boot> option.
+=item B<-o json -os> C<DIRECTORY>
+
+This converts the guest to files in C<DIRECTORY>. The metadata
+produced is a JSON file containing the majority of the data virt-v2v
+gathers during the conversion.
+See L</OUTPUT TO JSON> below.
+
=item B<-o null>
The guest is converted, but the final result is thrown away and no
@@ -140,6 +150,51 @@ Define the final guest in libvirt:
=back
+=head1 OUTPUT TO JSON
+
+The I<-o json> option produces the following files by default:
+
+ NAME.json JSON metadata.
+ NAME-sda, NAME-sdb, etc. Guest disk(s).
+
+where C<NAME> is the guest name.
+
+It is possible to change the pattern of the disks using the
+I<-oo json-disks-pattern=...> option: it allows parameters in form of
+C<%{...}> variables, for example:
+
+ -oo json-disks-pattern=disk%{DiskNo}.img
+
+Recognized variables are:
+
+=over 4
+
+=item C<%{DiskNo}>
+
+The index of the disk, starting from 1.
+
+=item C<%{DiskDeviceName}>
+
+The destination device of the disk, e.g. C<sda>, C<sdb>, etc.
+
+=item C<%{GuestName}>
+
+The name of the guest.
+
+=back
+
+Using a pattern it is possible use subdirectories for the disks,
+even with names depending on variables; for example:
+
+ -oo json-disks-pattern=%{GuestName}-%{DiskNo}/disk.img
+
+The default pattern is C<%{GuestName}-%{DiskDeviceName}>.
+
+If the literal C<%{...}> text is needed, it is possible to avoid the
+escape it with a leading C<%>; for example,
+C<%%{GuestName}-%{DiskNo}.img> will create file names for the
+disks like C<%%{GuestName}-1.img>, C<%%{GuestName}-2.img>, etc.
+
=head1 SEE ALSO
L<virt-v2v(1)>.
diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
index cf9464834..9a555c3be 100644
--- a/v2v/virt-v2v.pod
+++ b/v2v/virt-v2v.pod
@@ -425,6 +425,17 @@ instead.
Set the output method to OpenStack Glance. In this mode the converted
guest is uploaded to Glance. See L<virt-v2v-output-openstack(1)>.
+=item B<-o> B<json>
+
+Set the output method to I<json>.
+
+In this mode, the converted guest is written to a local directory
+specified by I<-os /dir> (the directory must exist), with a JSON file
+containing the majority of the metadata that virt-v2v gathered during
+the conversion.
+
+See L<virt-v2v-output-local(1)>.
+
=item B<-o> B<libvirt>
Set the output method to I<libvirt>. This is the default.
@@ -696,8 +707,8 @@ The location of the storage for the converted guest.
For I<-o libvirt>, this is a libvirt directory pool
(see S<C<virsh pool-list>>) or pool UUID.
-For I<-o local> and I<-o qemu>, this is a directory name. The
-directory must exist.
+For I<-o json>, I<-o local> and I<-o qemu>, this is a directory name.
+The directory must exist.
For I<-o rhv-upload>, this is the name of the destination Storage
Domain.
--
2.26.2

View File

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

View File

@ -1,4 +1,4 @@
From 31af609ecc65424bb3671c6873005f31fd1b80d4 Mon Sep 17 00:00:00 2001 From e7ff090884f5e32585e9683d35b72bca01e0a836 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com> From: Pino Toscano <ptoscano@redhat.com>
Date: Mon, 11 Feb 2019 19:28:00 +0100 Date: Mon, 11 Feb 2019 19:28:00 +0100
Subject: [PATCH] inspect: fix icon of RHEL Subject: [PATCH] inspect: fix icon of RHEL
@ -15,10 +15,10 @@ Thanks to Ray Strode for the hints.
1 file changed, 1 insertion(+), 1 deletion(-) 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/inspect-icon.c b/lib/inspect-icon.c diff --git a/lib/inspect-icon.c b/lib/inspect-icon.c
index 0edd3d1b0..443dc6dd3 100644 index 623591aa6..19f3f87af 100644
--- a/lib/inspect-icon.c --- a/lib/inspect-icon.c
+++ b/lib/inspect-icon.c +++ b/lib/inspect-icon.c
@@ -301,7 +301,7 @@ icon_rhel (guestfs_h *g, int major, size_t *size_r) @@ -317,7 +317,7 @@ icon_rhel (guestfs_h *g, int major, size_t *size_r)
if (major < 7) if (major < 7)
shadowman = "/usr/share/pixmaps/redhat/shadowman-transparent.png"; shadowman = "/usr/share/pixmaps/redhat/shadowman-transparent.png";
else else
@ -28,5 +28,5 @@ index 0edd3d1b0..443dc6dd3 100644
return get_png (g, shadowman, size_r, 102400); return get_png (g, shadowman, size_r, 102400);
} }
-- --
2.21.0 2.26.2

View File

@ -1,213 +0,0 @@
From 14cfe80643a7df4ddf412aebdf39543344c1cf6e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Golembiovsk=C3=BD?= <tgolembi@redhat.com>
Date: Thu, 22 Feb 2018 11:41:08 +0100
Subject: [PATCH] v2v: vdsm: add --vdsm-fixed-ovf option
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add option for -o vdsm that enables output of the modified OVF. oVirt
engine should already be able to consume the OVF, but let's not take any
chances and enable it only by command line argument. It can be made
default later when it receives proper testing.
Signed-off-by: Tomáš Golembiovský <tgolembi@redhat.com>
(cherry picked from commit 285014b290507865fd2020e44ea453af0262b624)
---
v2v/cmdline.ml | 10 ++++++++++
v2v/create_ovf.ml | 7 +++++++
v2v/create_ovf.mli | 9 +++++++++
v2v/output_vdsm.ml | 9 +++++++--
v2v/output_vdsm.mli | 1 +
v2v/test-v2v-o-vdsm-options.sh | 3 ++-
v2v/virt-v2v.pod | 20 ++++++++++++++++++++
7 files changed, 56 insertions(+), 3 deletions(-)
diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
index d88d0a579..75909ee77 100644
--- a/v2v/cmdline.ml
+++ b/v2v/cmdline.ml
@@ -79,6 +79,11 @@ let parse_cmdline () =
let vdsm_compat = ref "0.10" in
let set_vdsm_compat s = vdsm_compat := s in
+ let vdsm_ovf_flavour = ref Create_ovf.RHVExportStorageDomain in
+ let ovf_flavours_str = String.concat "|" Create_ovf.ovf_flavours in
+ let set_vdsm_ovf_flavour arg =
+ vdsm_ovf_flavour := Create_ovf.ovf_flavour_of_string arg in
+
let set_string_option_once optname optref arg =
match !optref with
| Some _ ->
@@ -251,6 +256,8 @@ let parse_cmdline () =
s_"Output VM UUID";
[ L"vdsm-ovf-output" ], Getopt.String ("-", set_string_option_once "--vdsm-ovf-output" vdsm_ovf_output),
s_"Output OVF file";
+ [ L"vdsm-ovf-flavour" ], Getopt.Symbol (ovf_flavours_str, Create_ovf.ovf_flavours, set_vdsm_ovf_flavour),
+ s_"Set the type of generated OVF (default rhvexp)";
[ L"vmtype" ], Getopt.String ("-", vmtype_warning),
s_"Ignored for backwards compatibility";
] in
@@ -327,6 +334,7 @@ read the man page virt-v2v(1).
let vdsm_vol_uuids = List.rev !vdsm_vol_uuids in
let vdsm_vm_uuid = !vdsm_vm_uuid in
let vdsm_ovf_output = Option.default "." !vdsm_ovf_output in
+ let vdsm_ovf_flavour = !vdsm_ovf_flavour in
(* No arguments and machine-readable mode? Print out some facts
* about what this binary supports.
@@ -343,6 +351,7 @@ read the man page virt-v2v(1).
List.iter (printf "input:%s\n") (Modules_list.input_modules ());
List.iter (printf "output:%s\n") (Modules_list.output_modules ());
List.iter (printf "convert:%s\n") (Modules_list.convert_modules ());
+ List.iter (printf "ovf:%s\n") Create_ovf.ovf_flavours;
exit 0
);
@@ -542,6 +551,7 @@ read the man page virt-v2v(1).
vm_uuid = vdsm_vm_uuid;
ovf_output = vdsm_ovf_output;
compat = vdsm_compat;
+ ovf_flavour = vdsm_ovf_flavour;
} in
Output_vdsm.output_vdsm os vdsm_options output_alloc,
output_format, output_alloc in
diff --git a/v2v/create_ovf.ml b/v2v/create_ovf.ml
index 0ec0a088c..d0735afce 100644
--- a/v2v/create_ovf.ml
+++ b/v2v/create_ovf.ml
@@ -33,6 +33,13 @@ type ovf_flavour =
| OVirt
| RHVExportStorageDomain
+let ovf_flavours = ["ovirt"; "rhvexp"]
+
+let ovf_flavour_of_string = function
+ | "ovirt" -> OVirt
+ | "rhvexp" -> RHVExportStorageDomain
+ | flav -> invalid_arg flav
+
(* We set the creation time to be the same for all dates in
* all metadata files. All dates in OVF are UTC.
*)
diff --git a/v2v/create_ovf.mli b/v2v/create_ovf.mli
index 8a8c7dd12..2d80660e3 100644
--- a/v2v/create_ovf.mli
+++ b/v2v/create_ovf.mli
@@ -20,6 +20,15 @@ type ovf_flavour =
| OVirt
| RHVExportStorageDomain
+(** The string representation of available OVF flavours. *)
+val ovf_flavours : string list
+
+(** Convert from a string to the corresponding OVF flavour.
+
+ Throw [Invalid_argument] if the string does not match any
+ valid flavour. *)
+val ovf_flavour_of_string : string -> ovf_flavour
+
(** Create OVF and related files for RHV.
The format for RHV export storage domain is described in:
diff --git a/v2v/output_vdsm.ml b/v2v/output_vdsm.ml
index ce286d327..b76a2e930 100644
--- a/v2v/output_vdsm.ml
+++ b/v2v/output_vdsm.ml
@@ -32,6 +32,7 @@ type vdsm_options = {
vm_uuid : string;
ovf_output : string;
compat : string;
+ ovf_flavour : Create_ovf.ovf_flavour;
}
class output_vdsm os vdsm_options output_alloc =
@@ -39,7 +40,7 @@ object
inherit output
method as_options =
- sprintf "-o vdsm -os %s%s%s --vdsm-vm-uuid %s --vdsm-ovf-output %s%s" os
+ sprintf "-o vdsm -os %s%s%s --vdsm-vm-uuid %s --vdsm-ovf-output %s%s%s" os
(String.concat ""
(List.map (sprintf " --vdsm-image-uuid %s") vdsm_options.image_uuids))
(String.concat ""
@@ -49,6 +50,10 @@ object
(match vdsm_options.compat with
| "0.10" -> "" (* currently this is the default, so don't print it *)
| s -> sprintf " --vdsm-compat=%s" s)
+ (match vdsm_options.ovf_flavour with
+ | Create_ovf.OVirt -> "--vdsm-ovf-flavour=ovf"
+ (* currently this is the default, so don't print it *)
+ | Create_ovf.RHVExportStorageDomain -> "")
method supported_firmware = [ TargetBIOS ]
@@ -176,7 +181,7 @@ object
vdsm_options.image_uuids
vdsm_options.vol_uuids
vdsm_options.vm_uuid
- Create_ovf.RHVExportStorageDomain in
+ vdsm_options.ovf_flavour in
(* Write it to the metadata file. *)
let file = vdsm_options.ovf_output // vdsm_options.vm_uuid ^ ".ovf" in
diff --git a/v2v/output_vdsm.mli b/v2v/output_vdsm.mli
index 401a71ec4..6ed684638 100644
--- a/v2v/output_vdsm.mli
+++ b/v2v/output_vdsm.mli
@@ -24,6 +24,7 @@ type vdsm_options = {
vm_uuid : string; (* --vdsm-vm-uuid *)
ovf_output : string; (* --vdsm-ovf-output *)
compat : string; (* --vdsm-compat=0.10|1.1 *)
+ ovf_flavour : Create_ovf.ovf_flavour;
}
(** Miscellaneous extra command line parameters used by VDSM. *)
diff --git a/v2v/test-v2v-o-vdsm-options.sh b/v2v/test-v2v-o-vdsm-options.sh
index 753efc4e7..4ad5d4aad 100755
--- a/v2v/test-v2v-o-vdsm-options.sh
+++ b/v2v/test-v2v-o-vdsm-options.sh
@@ -55,7 +55,8 @@ $VG virt-v2v --debug-gc \
--vdsm-vol-uuid VOL \
--vdsm-vm-uuid VM \
--vdsm-ovf-output $d/12345678-1234-1234-1234-123456789abc/master/vms/VM \
- --vdsm-compat=1.1
+ --vdsm-compat=1.1 \
+ --vdsm-ovf-flavour=ovirt
# Test the OVF metadata was created.
test -f $d/12345678-1234-1234-1234-123456789abc/master/vms/VM/VM.ovf
diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
index cced114f3..0ea5fa97f 100644
--- a/v2v/virt-v2v.pod
+++ b/v2v/virt-v2v.pod
@@ -759,6 +759,26 @@ hex digit can be C<0-9> or C<a-f>), conforming to S<OSF DCE 1.1>.
These options can only be used with I<-o vdsm>.
+=item B<--vdsm-ovf-flavour> flavour
+
+This option controls the format of the OVF generated at the end of conversion.
+Currently there are two possible flavours:
+
+=over 4
+
+=item rhevexp
+
+The OVF format used in RHV export storage domain.
+
+=item ovirt
+
+The OVF format understood by oVirt REST API.
+
+=back
+
+For backward compatibility the default is I<rhevexp>, but this may change in
+the future.
+
=item B<-v>
=item B<--verbose>
--
2.21.0

View File

@ -1,124 +0,0 @@
From 00ed208050cdb2178ac58878cb126504ebc7b311 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Thu, 22 Feb 2018 14:22:12 +0000
Subject: [PATCH] v2v: OVF: Code formatting.
Updates commit a52ed4b4454396eb13d2cdf5762292bff3104f66
("v2v: ovf: Create OVF more aligned with the standard") with some
small code refactoring and formatting.
(cherry picked from commit 9e83f3a2ccef4e91b0b3275b712df8b16e233cff)
---
v2v/create_ovf.ml | 73 ++++++++++++++++++++++++++---------------------
1 file changed, 41 insertions(+), 32 deletions(-)
diff --git a/v2v/create_ovf.ml b/v2v/create_ovf.ml
index d0735afce..0e07afea8 100644
--- a/v2v/create_ovf.ml
+++ b/v2v/create_ovf.ml
@@ -530,20 +530,16 @@ let rec create_ovf source targets guestcaps inspect
* For example normal disk section is in node <DiskSection> whereas in case of
* RHV export storage domain it is <Section xsi:type="ovf:DiskSection_Type">.
*)
-and get_flavoured_section ovf ovf_flavour ovirt_path rhv_path rhv_path_attr =
- let nodes =
- match ovf_flavour with
- | OVirt ->
- let nodes = path_to_nodes ovf ovirt_path in
- (match nodes with
+and get_flavoured_section ovf ovirt_path rhv_path rhv_path_attr = function
+ | OVirt ->
+ let nodes = path_to_nodes ovf ovirt_path in
+ (match nodes with
| [node] -> node
| [] | _::_::_ -> assert false)
- | RHVExportStorageDomain ->
- let nodes = path_to_nodes ovf rhv_path in
- try find_node_by_attr nodes rhv_path_attr
- with Not_found -> assert false
- in
- nodes
+ | RHVExportStorageDomain ->
+ let nodes = path_to_nodes ovf rhv_path in
+ try find_node_by_attr nodes rhv_path_attr
+ with Not_found -> assert false
(* This modifies the OVF DOM, adding a section for each disk. *)
and add_disks targets guestcaps output_alloc sd_uuid image_uuids vol_uuids
@@ -553,14 +549,19 @@ and add_disks targets guestcaps output_alloc sd_uuid image_uuids vol_uuids
match nodes with
| [] | _::_::_ -> assert false
| [node] -> node in
- let disk_section = get_flavoured_section ovf ovf_flavour
- ["ovf:Envelope"; "DiskSection"]
- ["ovf:Envelope"; "Section"]
- ("xsi:type", "ovf:DiskSection_Type") in
- let virtualhardware_section = get_flavoured_section ovf ovf_flavour
- ["ovf:Envelope"; "VirtualSystem"; "VirtualHardwareSection"]
- ["ovf:Envelope"; "Content"; "Section"]
- ("xsi:type", "ovf:VirtualHardwareSection_Type") in
+ let disk_section =
+ get_flavoured_section ovf
+ ["ovf:Envelope"; "DiskSection"]
+ ["ovf:Envelope"; "Section"]
+ ("xsi:type", "ovf:DiskSection_Type")
+ ovf_flavour in
+ let virtualhardware_section =
+ get_flavoured_section ovf
+ ["ovf:Envelope"; "VirtualSystem";
+ "VirtualHardwareSection"]
+ ["ovf:Envelope"; "Content"; "Section"]
+ ("xsi:type", "ovf:VirtualHardwareSection_Type")
+ ovf_flavour in
(* Iterate over the disks, adding them to the OVF document. *)
List.iteri (
@@ -693,14 +694,19 @@ and add_disks targets guestcaps output_alloc sd_uuid image_uuids vol_uuids
(* This modifies the OVF DOM, adding a section for each NIC. *)
and add_networks nics guestcaps ovf_flavour ovf =
- let network_section = get_flavoured_section ovf ovf_flavour
- ["ovf:Envelope"; "NetworkSection"]
- ["ovf:Envelope"; "Section"]
- ("xsi:type", "ovf:NetworkSection_Type") in
- let virtualhardware_section = get_flavoured_section ovf ovf_flavour
- ["ovf:Envelope"; "VirtualSystem"; "VirtualHardwareSection"]
- ["ovf:Envelope"; "Content"; "Section"]
- ("xsi:type", "ovf:VirtualHardwareSection_Type") in
+ let network_section =
+ get_flavoured_section ovf
+ ["ovf:Envelope"; "NetworkSection"]
+ ["ovf:Envelope"; "Section"]
+ ("xsi:type", "ovf:NetworkSection_Type")
+ ovf_flavour in
+ let virtualhardware_section =
+ get_flavoured_section ovf
+ ["ovf:Envelope"; "VirtualSystem";
+ "VirtualHardwareSection"]
+ ["ovf:Envelope"; "Content"; "Section"]
+ ("xsi:type", "ovf:VirtualHardwareSection_Type")
+ ovf_flavour in
(* Iterate over the NICs, adding them to the OVF document. *)
List.iteri (
@@ -761,10 +767,13 @@ and add_sound_card sound ovf_flavour ovf =
match device with
| Some device ->
- let virtualhardware_section = get_flavoured_section ovf ovf_flavour
- ["ovf:Envelope"; "VirtualSystem"; "VirtualHardwareSection"]
- ["ovf:Envelope"; "Content"; "Section"]
- ("xsi:type", "ovf:VirtualHardwareSection_Type") in
+ let virtualhardware_section =
+ get_flavoured_section ovf
+ ["ovf:Envelope"; "VirtualSystem";
+ "VirtualHardwareSection"]
+ ["ovf:Envelope"; "Content"; "Section"]
+ ("xsi:type", "ovf:VirtualHardwareSection_Type")
+ ovf_flavour in
let item =
e "Item" [] [
--
2.21.0

View File

@ -0,0 +1,48 @@
From df8794643644c742b7cfced948eee4519b38a643 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Fri, 12 Apr 2019 17:28:12 +0200
Subject: [PATCH] v2v: warn when the guest has direct network interfaces
(RHBZ#1518539)
virt-v2v obviously cannot convert this kind of devices, since they are
specific to the host of the hypervisor. Thus, emit a warning about the
presence of direct network interfaces, so at least this can be noticed
when converting a guest.
(cherry picked from commit 1629ec6a5639cf5e226e80bcee749ae8851b1fae)
---
v2v/parse_libvirt_xml.ml | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/v2v/parse_libvirt_xml.ml b/v2v/parse_libvirt_xml.ml
index d5d78d367..b9970cee8 100644
--- a/v2v/parse_libvirt_xml.ml
+++ b/v2v/parse_libvirt_xml.ml
@@ -492,6 +492,24 @@ let parse_libvirt_xml ?conn xml =
)
in
+ (* Check for direct attachments to physical network interfaces.
+ * (RHBZ#1518539)
+ *)
+ let () =
+ let obj = Xml.xpath_eval_expression xpathctx "/domain/devices/interface[@type='direct']" in
+ let nr_nodes = Xml.xpathobj_nr_nodes obj in
+ if nr_nodes > 0 then (
+ (* Sadly fn_ in ocaml-gettext seems broken, and always returns the
+ * singular string no matter what. Work around this by using a simple
+ * string with sn_ (which works), and outputting it as a whole.
+ *)
+ let msg = sn_ "this guest has a direct network interface which will be ignored"
+ "this guest has direct network interfaces which will be ignored"
+ nr_nodes in
+ warning "%s" msg
+ )
+ in
+
({
s_hypervisor = hypervisor;
s_name = name; s_orig_name = name;
--
2.26.2

View File

@ -1,127 +0,0 @@
From 83b5f589231da2ab6d04680f42c37dc6058cbe6e Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 20 Feb 2018 15:21:48 +0000
Subject: [PATCH] v2v: DOM: Add doc_to_string function.
Convert a document to an in-memory string.
(cherry picked from commit 802c8635cc2537a7d4b7af8981c670e2fdbb2675)
---
v2v/DOM.ml | 61 +++++++++++++++++++++++++++++++++--------------------
v2v/DOM.mli | 3 +++
2 files changed, 41 insertions(+), 23 deletions(-)
diff --git a/v2v/DOM.ml b/v2v/DOM.ml
index 7f66e0920..8b106224b 100644
--- a/v2v/DOM.ml
+++ b/v2v/DOM.ml
@@ -46,43 +46,48 @@ let e name attrs children =
* we will be writing, ie. libvirt XML and OVF metadata, where
* whitespace is generally not significant, but readability is useful.
*)
-let rec node_to_chan ?(indent = 0) chan = function
- | PCData str -> output_string chan (xml_quote_pcdata str)
+let rec node_to_buf ?(indent = 0) buf = function
+ | PCData str ->
+ Buffer.add_string buf (xml_quote_pcdata str)
| Comment str ->
- output_spaces chan indent;
- fprintf chan "<!-- %s -->" (xml_quote_pcdata str)
- | Element e -> element_to_chan ~indent chan e
-and element_to_chan ?(indent = 0) chan
+ buffer_add_spaces buf indent;
+ bprintf buf "<!-- %s -->" (xml_quote_pcdata str)
+ | Element e ->
+ element_to_buf ~indent buf e
+and element_to_buf ?(indent = 0) buf
{ e_name = name; e_attrs = attrs; e_children = children } =
- output_spaces chan indent;
- fprintf chan "<%s" name;
- List.iter (fun (n, v) -> fprintf chan " %s='%s'" n (xml_quote_attr v)) attrs;
+ buffer_add_spaces buf indent;
+ bprintf buf "<%s" name;
+ List.iter (fun (n, v) -> bprintf buf " %s='%s'" n (xml_quote_attr v)) attrs;
if children <> [] then (
- output_string chan ">";
+ Buffer.add_string buf ">";
let last_child_was_element = ref false in
List.iter (
function
| Element _ as child ->
last_child_was_element := true;
- output_char chan '\n';
- node_to_chan ~indent:(indent+2) chan child;
+ Buffer.add_char buf '\n';
+ node_to_buf ~indent:(indent+2) buf child;
| PCData _ as child ->
last_child_was_element := false;
- node_to_chan ~indent:(indent+2) chan child;
+ node_to_buf ~indent:(indent+2) buf child;
| Comment _ as child ->
last_child_was_element := true;
- output_char chan '\n';
- node_to_chan ~indent:(indent+2) chan child;
+ Buffer.add_char buf '\n';
+ node_to_buf ~indent:(indent+2) buf child;
) children;
if !last_child_was_element then (
- output_char chan '\n';
- output_spaces chan indent
+ Buffer.add_char buf '\n';
+ buffer_add_spaces buf indent
);
- fprintf chan "</%s>" name
+ bprintf buf "</%s>" name
) else (
- output_string chan "/>"
+ Buffer.add_string buf "/>"
)
+and buffer_add_spaces buf n =
+ Buffer.add_string buf (String.spaces n)
+
(* Quote XML <element attr='...'> content. Note you must use single
* quotes around the attribute.
*)
@@ -99,10 +104,20 @@ and xml_quote_pcdata str =
let str = String.replace str ">" "&gt;" in
str
-let doc_to_chan chan (Doc doc) =
- fprintf chan "<?xml version='1.0' encoding='utf-8'?>\n";
- element_to_chan chan doc;
- fprintf chan "\n"
+let doc_to_buf buf (Doc doc) =
+ bprintf buf "<?xml version='1.0' encoding='utf-8'?>\n";
+ element_to_buf buf doc;
+ bprintf buf "\n"
+
+let doc_to_string doc =
+ let buf = Buffer.create 4096 in
+ doc_to_buf buf doc;
+ Buffer.contents buf
+
+let doc_to_chan chan doc =
+ let buf = Buffer.create 4096 in
+ doc_to_buf buf doc;
+ Buffer.output_buffer chan buf
let path_to_nodes (Doc doc) path =
match path with
diff --git a/v2v/DOM.mli b/v2v/DOM.mli
index 1aa89b7e7..99223c389 100644
--- a/v2v/DOM.mli
+++ b/v2v/DOM.mli
@@ -60,6 +60,9 @@ v}
v}
*)
+val doc_to_string : doc -> string
+(** Convert a document to a string representation. *)
+
val doc_to_chan : out_channel -> doc -> unit
(** Write the XML document to an output channel. *)
--
2.21.0

View File

@ -1,4 +1,4 @@
From 6ea20c9a03cb9ecadd60a1197499a4eaa4593416 Mon Sep 17 00:00:00 2001 From de267e07b9b26d2f89470d4305d7259edb24663b Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com> From: Pino Toscano <ptoscano@redhat.com>
Date: Fri, 12 Apr 2019 16:19:43 +0200 Date: Fri, 12 Apr 2019 16:19:43 +0200
Subject: [PATCH] v2v: update documentation on nbdkit (RHBZ#1605242) Subject: [PATCH] v2v: update documentation on nbdkit (RHBZ#1605242)
@ -8,14 +8,14 @@ version instead of recommending to build nbdkit from sources.
(cherry picked from commit 0704d8eb0bcc8139886eb4291f75a3ca49a91e58) (cherry picked from commit 0704d8eb0bcc8139886eb4291f75a3ca49a91e58)
--- ---
v2v/virt-v2v.pod | 28 ++-------------------------- v2v/virt-v2v-input-vmware.pod | 28 ++--------------------------
1 file changed, 2 insertions(+), 26 deletions(-) 1 file changed, 2 insertions(+), 26 deletions(-)
diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod diff --git a/v2v/virt-v2v-input-vmware.pod b/v2v/virt-v2v-input-vmware.pod
index f4d200e3d..74536a2a6 100644 index 2b6dbaeec..b3ebda182 100644
--- a/v2v/virt-v2v.pod --- a/v2v/virt-v2v-input-vmware.pod
+++ b/v2v/virt-v2v.pod +++ b/v2v/virt-v2v-input-vmware.pod
@@ -1657,32 +1657,8 @@ library is permitted by the license. @@ -197,32 +197,8 @@ library is permitted by the license.
=item 2. =item 2.
@ -51,5 +51,5 @@ index f4d200e3d..74536a2a6 100644
=item 3. =item 3.
-- --
2.21.0 2.26.2

View File

@ -1,138 +0,0 @@
From ae2d0a507af53563d0b70d28654c9c60a857fd10 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Thu, 22 Feb 2018 11:43:33 +0000
Subject: [PATCH] v2v: Add -op (output password file) option.
Currently unused, in a future commit this will allow you to pass in a
password to be used when connecting to the target hypervisor.
(cherry picked from commit a4e181137a38f5767dd1bf05dc482959cb7283be)
---
v2v/cmdline.ml | 18 ++++++++++++++++++
v2v/test-v2v-docs.sh | 2 +-
v2v/virt-v2v.pod | 7 +++++++
3 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
index 75909ee77..2a067741e 100644
--- a/v2v/cmdline.ml
+++ b/v2v/cmdline.ml
@@ -62,6 +62,7 @@ let parse_cmdline () =
let output_conn = ref None in
let output_format = ref None in
let output_name = ref None in
+ let output_password = ref None in
let output_storage = ref None in
let password_file = ref None in
let vddk_config = ref None in
@@ -219,6 +220,8 @@ let parse_cmdline () =
s_"Set output format";
[ M"on" ], Getopt.String ("name", set_string_option_once "-on" output_name),
s_"Rename guest when converting";
+ [ M"op" ], Getopt.String ("filename", set_string_option_once "-op" output_password),
+ s_"Use password from file to connect to output hypervisor";
[ M"os" ], Getopt.String ("storage", set_string_option_once "-os" output_storage),
s_"Set output storage location";
[ L"password-file" ], Getopt.String ("file", set_string_option_once "--password-file" password_file),
@@ -314,6 +317,7 @@ read the man page virt-v2v(1).
let output_format = !output_format in
let output_mode = !output_mode in
let output_name = !output_name in
+ let output_password = !output_password in
let output_storage = !output_storage in
let password_file = !password_file in
let print_source = !print_source in
@@ -461,6 +465,8 @@ read the man page virt-v2v(1).
| `Glance ->
if output_conn <> None then
error_option_cannot_be_used_in_output_mode "glance" "-oc";
+ if output_password <> None then
+ error_option_cannot_be_used_in_output_mode "glance" "-op";
if output_storage <> None then
error_option_cannot_be_used_in_output_mode "glance" "-os";
if qemu_boot then
@@ -472,6 +478,8 @@ read the man page virt-v2v(1).
| `Not_set
| `Libvirt ->
+ if output_password <> None then
+ error_option_cannot_be_used_in_output_mode "libvirt" "-op";
let output_storage = Option.default "default" output_storage in
if qemu_boot then
error_option_cannot_be_used_in_output_mode "libvirt" "--qemu-boot";
@@ -481,6 +489,8 @@ read the man page virt-v2v(1).
output_format, output_alloc
| `Local ->
+ if output_password <> None then
+ error_option_cannot_be_used_in_output_mode "local" "-op";
let os =
match output_storage with
| None ->
@@ -500,6 +510,8 @@ read the man page virt-v2v(1).
error_option_cannot_be_used_in_output_mode "null" "-oc";
if output_format <> None then
error_option_cannot_be_used_in_output_mode "null" "-of";
+ if output_password <> None then
+ error_option_cannot_be_used_in_output_mode "null" "-op";
if output_storage <> None then
error_option_cannot_be_used_in_output_mode "null" "-os";
if qemu_boot then
@@ -509,6 +521,8 @@ read the man page virt-v2v(1).
Some "raw", Sparse
| `QEmu ->
+ if output_password <> None then
+ error_option_cannot_be_used_in_output_mode "qemu" "-op";
let os =
match output_storage with
| None ->
@@ -520,6 +534,8 @@ read the man page virt-v2v(1).
output_format, output_alloc
| `RHV ->
+ if output_password <> None then
+ error_option_cannot_be_used_in_output_mode "rhv" "-op";
let os =
match output_storage with
| None ->
@@ -531,6 +547,8 @@ read the man page virt-v2v(1).
output_format, output_alloc
| `VDSM ->
+ if output_password <> None then
+ error_option_cannot_be_used_in_output_mode "vdsm" "-op";
let os =
match output_storage with
| None ->
diff --git a/v2v/test-v2v-docs.sh b/v2v/test-v2v-docs.sh
index 5d034c465..0e3bd916a 100755
--- a/v2v/test-v2v-docs.sh
+++ b/v2v/test-v2v-docs.sh
@@ -22,4 +22,4 @@ $TEST_FUNCTIONS
skip_if_skipped
$top_srcdir/podcheck.pl virt-v2v.pod virt-v2v \
- --ignore=--debug-overlay,--ic,--if,--it,--no-trim,--oa,--oc,--of,--on,--os,--vmtype
+ --ignore=--debug-overlay,--ic,--if,--it,--no-trim,--oa,--oc,--of,--on,--op,--os,--vmtype
diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
index 0ea5fa97f..00ba45555 100644
--- a/v2v/virt-v2v.pod
+++ b/v2v/virt-v2v.pod
@@ -569,6 +569,13 @@ If not specified, then the input format is used.
Rename the guest when converting it. If this option is not used then
the output name is the same as the input name.
+=item B<-op> file
+
+Supply a file containing a password to be used when connecting to the
+target hypervisor. Note the file should contain the whole password,
+B<without any trailing newline>, and for security the file should have
+mode C<0600> so that others cannot read it.
+
=item B<-os> storage
The location of the storage for the converted guest.
--
2.21.0

View File

@ -0,0 +1,57 @@
From 51367a1f2d4a5c54564a6bcaf8c193de643d3ee4 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Wed, 27 Feb 2019 17:51:59 +0100
Subject: [PATCH] v2v: linux: do not uninstall open-vm-tools w/ ubuntu-server
ubuntu-server depends on open-vm-tools on Ubuntu, so if v2v tries to
uninstall open-vm-tools then dpkg will (rightfully) fail with a
dependency issue.
Since open-vm-tools is harmless after the conversion anyway (it will
not even run), then do not attempt to uninstall it if ubuntu-server is
installed too.
Followup of commit 2bebacf8bf611f0f80a66915f78653ce30b38129.
Thanks to: Ming Xie.
(cherry picked from commit 1a4fd822ef057764f809cddce642b3223756629e)
---
v2v/convert_linux.ml | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml
index 3d61400b5..b4b2f24c4 100644
--- a/v2v/convert_linux.ml
+++ b/v2v/convert_linux.ml
@@ -289,6 +289,18 @@ let convert (g : G.guestfs) inspect source output rcaps =
(* Uninstall VMware Tools. *)
let remove = ref [] and libraries = ref [] in
+ (* On Ubuntu, the ubuntu-server metapackage depends on
+ * open-vm-tools, and thus any attempt to remove it will cause
+ * dependency issues. Hence, special case this situation, and
+ * leave open-vm-tools installed in this case.
+ *)
+ let has_ubuntu_server =
+ if family = `Debian_family then
+ List.exists (
+ fun { G.app2_name = name } ->
+ name = "ubuntu-server"
+ ) inspect.i_apps
+ else false in
List.iter (
fun { G.app2_name = name } ->
if String.is_prefix name "vmware-tools-libraries-" then
@@ -301,7 +313,7 @@ let convert (g : G.guestfs) inspect source output rcaps =
List.push_front name remove
else if String.is_prefix name "open-vm-tools-" then
List.push_front name remove
- else if name = "open-vm-tools" then
+ else if name = "open-vm-tools" && not has_ubuntu_server then
List.push_front name remove
) inspect.i_apps;
let libraries = !libraries in
--
2.26.2

View File

@ -1,35 +0,0 @@
From 311d8dff12b8079b7eb9d6d2d917a9c6883928a4 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Thu, 22 Mar 2018 10:28:36 +0000
Subject: [PATCH] v2v: cmdline: Move definition to before its only use.
(cherry picked from commit 3167ce1f91667de4c4fe1885bb33c06ee6fa38c5)
---
v2v/cmdline.ml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
index 2a067741e..a83fcbae0 100644
--- a/v2v/cmdline.ml
+++ b/v2v/cmdline.ml
@@ -81,7 +81,6 @@ let parse_cmdline () =
let set_vdsm_compat s = vdsm_compat := s in
let vdsm_ovf_flavour = ref Create_ovf.RHVExportStorageDomain in
- let ovf_flavours_str = String.concat "|" Create_ovf.ovf_flavours in
let set_vdsm_ovf_flavour arg =
vdsm_ovf_flavour := Create_ovf.ovf_flavour_of_string arg in
@@ -183,7 +182,8 @@ let parse_cmdline () =
let i_options =
String.concat "|" (Modules_list.input_modules ())
and o_options =
- String.concat "|" (Modules_list.output_modules ()) in
+ String.concat "|" (Modules_list.output_modules ())
+ and ovf_flavours_str = String.concat "|" Create_ovf.ovf_flavours in
let argspec = [
[ S 'b'; L"bridge" ], Getopt.String ("in:out", add_bridge),
--
2.21.0

View File

@ -0,0 +1,36 @@
From 6239ce21ea4d47914aa149cee724e998c287d26c Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Wed, 20 Mar 2019 16:55:05 +0100
Subject: [PATCH] v2v: linux: canonicalize module path for arch detection
(RHBZ#1690574)
Kernel modules can be also symlinks to files available outside the
"canonical" module directory; the "file" API, used by the
"file-architecture" API, return the actual type of a file (so symlinks,
block devices, etc), and thus "file-architecture" fails on symlinks.
To prevent this situation, canonicalize the path of the module picked
for architecture detection: this way, "file-architecture" will act on a
real file.
(cherry picked from commit 0a093035d485b3c2e66d56541ebe159f1b632ba6)
---
v2v/linux_kernels.ml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/v2v/linux_kernels.ml b/v2v/linux_kernels.ml
index 3313aabc7..889ec2f2a 100644
--- a/v2v/linux_kernels.ml
+++ b/v2v/linux_kernels.ml
@@ -189,7 +189,7 @@ let detect_kernels (g : G.guestfs) inspect family bootloader =
*)
let arch =
let any_module = modpath ^ List.hd modules in
- g#file_architecture any_module in
+ g#file_architecture (g#realpath any_module) in
(* Just return the module names, without path or extension. *)
let modules = List.filter_map (
--
2.26.2

View File

@ -0,0 +1,61 @@
From 10afd834b5e1787cb2b22fce96de30baf37b5b2b Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Wed, 20 Mar 2019 12:32:02 +0100
Subject: [PATCH] v2v: linux: improve arch detection from modules
(RHBZ#1690574)
Try to look for a well known kernel module (so far only virtio, or kvm)
to use for detecting the architecture of a kernel. This way, we can
avoid picking 3rd party modules that cause troubles.
(cherry picked from commit 363b5e0b4ecebe861a9aafe8bce5a8390b54571c)
---
v2v/linux_kernels.ml | 30 +++++++++++++++++++++++++++---
1 file changed, 27 insertions(+), 3 deletions(-)
diff --git a/v2v/linux_kernels.ml b/v2v/linux_kernels.ml
index 889ec2f2a..30160f0da 100644
--- a/v2v/linux_kernels.ml
+++ b/v2v/linux_kernels.ml
@@ -185,11 +185,35 @@ let detect_kernels (g : G.guestfs) inspect family bootloader =
assert (List.length modules > 0);
(* Determine the kernel architecture by looking at the
- * architecture of an arbitrary kernel module.
+ * architecture of a kernel module.
+ *
+ * To avoid architecture detection issues with 3rd party
+ * modules (RHBZ#1690574), try to pick one of the well
+ * known modules, if available. Otherwise, an arbitrary
+ * module is used.
*)
let arch =
- let any_module = modpath ^ List.hd modules in
- g#file_architecture (g#realpath any_module) in
+ (* Well known kernel modules. *)
+ let candidates = [ "virtio"; "kvm" ] in
+ let all_candidates = List.flatten (
+ List.map (
+ fun f ->
+ [ "/" ^ f ^ ".o"; "/" ^ f ^ ".ko"; "/" ^ f ^ ".ko.xz" ]
+ ) candidates
+ ) in
+ let candidate =
+ try
+ List.find (
+ fun m ->
+ List.exists (String.is_suffix m) all_candidates
+ ) modules
+ with Not_found ->
+ (* No known module found, pick an arbitrary one
+ * (the first).
+ *)
+ List.hd modules in
+ let candidate = modpath ^ candidate in
+ g#file_architecture (g#realpath candidate) in
(* Just return the module names, without path or extension. *)
let modules = List.filter_map (
--
2.26.2

View File

@ -1,4 +1,4 @@
From c7942097bff8cbbfbee34e1750223c308f32f8a4 Mon Sep 17 00:00:00 2001 From 54b63460b7602ac5c68d6e58ab60e7f85877cefc Mon Sep 17 00:00:00 2001
From: Martin Kletzander <mkletzan@redhat.com> From: Martin Kletzander <mkletzan@redhat.com>
Date: Mon, 27 May 2019 13:30:05 +0200 Date: Mon, 27 May 2019 13:30:05 +0200
Subject: [PATCH] Use proper label for nbdkit sockets Subject: [PATCH] Use proper label for nbdkit sockets
@ -33,10 +33,10 @@ Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2 files changed, 2 insertions(+), 2 deletions(-) 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/v2v/input_libvirt_vddk.ml b/v2v/input_libvirt_vddk.ml diff --git a/v2v/input_libvirt_vddk.ml b/v2v/input_libvirt_vddk.ml
index 0b3ed7af9..5e8e60bd2 100644 index 97c7cb532..567233d58 100644
--- a/v2v/input_libvirt_vddk.ml --- a/v2v/input_libvirt_vddk.ml
+++ b/v2v/input_libvirt_vddk.ml +++ b/v2v/input_libvirt_vddk.ml
@@ -292,7 +292,7 @@ object @@ -290,7 +290,7 @@ object
add_arg "--newstyle"; (* use newstyle NBD protocol *) add_arg "--newstyle"; (* use newstyle NBD protocol *)
add_arg "--exportname"; add_arg "/"; add_arg "--exportname"; add_arg "/";
if have_selinux then ( (* label the socket so qemu can open it *) if have_selinux then ( (* label the socket so qemu can open it *)
@ -46,10 +46,10 @@ index 0b3ed7af9..5e8e60bd2 100644
(* Name of the plugin. Everything following is a plugin parameter. *) (* Name of the plugin. Everything following is a plugin parameter. *)
diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml
index 79a2fc8fd..fc33e5033 100644 index 77c39107e..c2a5c72c7 100644
--- a/v2v/output_rhv_upload.ml --- a/v2v/output_rhv_upload.ml
+++ b/v2v/output_rhv_upload.ml +++ b/v2v/output_rhv_upload.ml
@@ -230,7 +230,7 @@ See also \"OUTPUT TO RHV\" in the virt-v2v(1) manual.") @@ -217,7 +217,7 @@ See also the virt-v2v-output-rhv(1) manual.")
let args = let args =
(* label the socket so qemu can open it *) (* label the socket so qemu can open it *)
if have_selinux then if have_selinux then
@ -59,5 +59,5 @@ index 79a2fc8fd..fc33e5033 100644
args in args in
-- --
2.21.0 2.26.2

View File

@ -1,247 +0,0 @@
From 1b4c00a3ec7c0618e8557e1e71d5782527a94828 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Wed, 4 Apr 2018 18:18:32 +0200
Subject: [PATCH] v2v: OVF: write ovirt:id attribute for the OS in OVirt
flavour
When writing the OVF in OVirt flavour, add a ovirt:id attribute to the
OperatingSystemSection tag: this attribute represents the numeric value
of the ostype ID, which is ignored by oVirt when parsing OVFs in API
mode.
(cherry picked from commit 593a19cc86cfa8f24c66518c8ba21222550b066a)
---
v2v/create_ovf.ml | 202 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 201 insertions(+), 1 deletion(-)
diff --git a/v2v/create_ovf.ml b/v2v/create_ovf.ml
index 0e07afea8..730ab64b4 100644
--- a/v2v/create_ovf.ml
+++ b/v2v/create_ovf.ml
@@ -242,6 +242,203 @@ and get_ostype = function
typ distro major minor arch product;
"Unassigned"
+(* Determine the ovirt:id attribute from libguestfs inspection.
+ * See ovirt-engine sources, file:
+ * packaging/conf/osinfo-defaults.properties
+ * and also:
+ * https://bugzilla.redhat.com/show_bug.cgi?id=1219857#c9
+ *)
+and get_ovirt_osid = function
+ | { i_type = "linux"; i_distro = ("rhel"|"centos"); i_major_version = 3;
+ i_arch = "i386" } ->
+ 9
+
+ | { i_type = "linux"; i_distro = ("rhel"|"centos"); i_major_version = 3;
+ i_arch = "x86_64" } ->
+ 15
+
+ | { i_type = "linux"; i_distro = ("rhel"|"centos"); i_major_version = 4;
+ i_arch = "i386" } ->
+ 8
+
+ | { i_type = "linux"; i_distro = ("rhel"|"centos"); i_major_version = 4;
+ i_arch = "x86_64" } ->
+ 14
+
+ | { i_type = "linux"; i_distro = ("rhel"|"centos"); i_major_version = 5;
+ i_arch = "i386" } ->
+ 7
+
+ | { i_type = "linux"; i_distro = ("rhel"|"centos"); i_major_version = 5;
+ i_arch = "x86_64" } ->
+ 13
+
+ | { i_type = "linux"; i_distro = ("rhel"|"centos"); i_major_version = 6;
+ i_arch = "i386" } ->
+ 18
+
+ | { i_type = "linux"; i_distro = ("rhel"|"centos"); i_major_version = 6;
+ i_arch = "x86_64" } ->
+ 19
+
+ | { i_type = "linux"; i_distro = ("rhel"|"centos"); i_major_version = 6;
+ i_minor_version = min; i_arch = ("ppc64"|"ppc64le") } when min >= 9 ->
+ 1007
+
+ | { i_type = "linux"; i_distro = ("rhel"|"centos"); i_major_version = 6;
+ i_arch = ("ppc64"|"ppc64le") } ->
+ 1003
+
+ | { i_type = "linux"; i_distro = ("rhel"|"centos"); i_major_version = 7;
+ i_arch = "x86_64" } ->
+ 24
+
+ | { i_type = "linux"; i_distro = ("rhel"|"centos"); i_major_version = 7;
+ i_arch = ("ppc64"|"ppc64le") } ->
+ 1006
+
+ | { i_type = "linux"; i_distro = ("rhel"|"centos"); i_major_version = 7;
+ i_arch = "s390x" } ->
+ 2003
+
+ | { i_type = "linux"; i_distro = "sles"; i_major_version = maj;
+ i_arch = "x86_64" } when maj >= 11 ->
+ 1193
+
+ | { i_type = "linux"; i_distro = "sles"; i_major_version = maj;
+ i_arch = ("ppc64"|"ppc64le") } when maj >= 11 ->
+ 1004
+
+ | { i_type = "linux"; i_distro = "sles"; i_major_version = maj;
+ i_arch = "s390x" } when maj >= 12 ->
+ 2004
+
+ (* Only Debian 7 is available, so use it for any 7+ version. *)
+ | { i_type = "linux"; i_distro = "debian"; i_major_version = v }
+ when v >= 7 ->
+ 1300
+
+ (* Only Ubuntu 12.04 to 14.04 are available, so use them starting
+ * from 12.04, and 14.04 for anything after it.
+ *)
+ | { i_type = "linux"; i_distro = "ubuntu"; i_major_version = v;
+ i_arch = ("ppc64"|"ppc64le") } when v >= 14 ->
+ 1005
+
+ | { i_type = "linux"; i_distro = "ubuntu"; i_major_version = v;
+ i_arch = "s390x" } when v >= 16 ->
+ 2005
+
+ | { i_type = "linux"; i_distro = "ubuntu"; i_major_version = v }
+ when v >= 14 ->
+ 1256
+
+ | { i_type = "linux"; i_distro = "ubuntu"; i_major_version = 12;
+ i_minor_version = 4 } ->
+ 1252
+
+ | { i_type = "linux"; i_distro = "ubuntu"; i_major_version = 12;
+ i_minor_version = 10 } ->
+ 1253
+
+ | { i_type = "linux"; i_distro = "ubuntu"; i_major_version = 13;
+ i_minor_version = 4 } ->
+ 1254
+
+ | { i_type = "linux"; i_distro = "ubuntu"; i_major_version = 13;
+ i_minor_version = 10 } ->
+ 1255
+
+ | { i_type = "linux"; i_arch = ("ppc64"|"ppc64le") } ->
+ 1002
+
+ | { i_type = "linux"; i_arch = "s390x" } ->
+ 2002
+
+ | { i_type = "linux" } ->
+ 5
+
+ | { i_type = "windows"; i_major_version = 5; i_minor_version = 1 } ->
+ 1 (* no architecture differentiation of XP on RHV *)
+
+ | { i_type = "windows"; i_major_version = 5; i_minor_version = 2;
+ i_product_name = product } when String.find product "XP" >= 0 ->
+ 1 (* no architecture differentiation of XP on RHV *)
+
+ | { i_type = "windows"; i_major_version = 5; i_minor_version = 2;
+ i_arch = "i386" } ->
+ 3
+
+ | { i_type = "windows"; i_major_version = 5; i_minor_version = 2;
+ i_arch = "x86_64" } ->
+ 10
+
+ | { i_type = "windows"; i_major_version = 6; i_minor_version = 0;
+ i_arch = "i386" } ->
+ 4
+
+ | { i_type = "windows"; i_major_version = 6; i_minor_version = 0;
+ i_arch = "x86_64" } ->
+ 16
+
+ | { i_type = "windows"; i_major_version = 6; i_minor_version = 1;
+ i_arch = "i386" } ->
+ 11
+
+ | { i_type = "windows"; i_major_version = 6; i_minor_version = 1;
+ i_arch = "x86_64"; i_product_variant = "Client" } ->
+ 12
+
+ | { i_type = "windows"; i_major_version = 6; i_minor_version = 1;
+ i_arch = "x86_64" } ->
+ 17
+
+ | { i_type = "windows"; i_major_version = 6; i_minor_version = 2;
+ i_arch = "i386" } ->
+ 20
+
+ | { i_type = "windows"; i_major_version = 6; i_minor_version = 2;
+ i_arch = "x86_64"; i_product_variant = "Client" } ->
+ 21
+
+ | { i_type = "windows"; i_major_version = 6; i_minor_version = 2;
+ i_arch = "x86_64" } ->
+ 23
+
+ (* Treat Windows 8.1 client like Windows 8. See:
+ * https://bugzilla.redhat.com/show_bug.cgi?id=1309580#c4
+ *)
+ | { i_type = "windows"; i_major_version = 6; i_minor_version = 3;
+ i_arch = "i386"; i_product_variant = "Client" } ->
+ 20
+
+ | { i_type = "windows"; i_major_version = 6; i_minor_version = 3;
+ i_arch = "x86_64"; i_product_variant = "Client" } ->
+ 21
+
+ | { i_type = "windows"; i_major_version = 6; i_minor_version = 3;
+ i_arch = "x86_64" } ->
+ 23
+
+ | { i_type = "windows"; i_major_version = 10; i_minor_version = 0;
+ i_arch = "i386" } ->
+ 26
+
+ | { i_type = "windows"; i_major_version = 10; i_minor_version = 0;
+ i_arch = "x86_64"; i_product_variant = "Client" } ->
+ 27
+
+ | { i_type = "windows"; i_major_version = 10; i_minor_version = 0;
+ i_arch = "x86_64" } ->
+ 29
+
+ | { i_type = typ; i_distro = distro;
+ i_major_version = major; i_minor_version = minor; i_arch = arch;
+ i_product_name = product } ->
+ warning (f_"unknown guest operating system: %s %s %d.%d %s (%s)")
+ typ distro major minor arch product;
+ 0
+
(* Set the <Origin/> element based on the source hypervisor.
* https://bugzilla.redhat.com/show_bug.cgi?id=1342398#c6
* https://gerrit.ovirt.org/#/c/59147/
@@ -321,6 +518,7 @@ let rec create_ovf source targets guestcaps inspect
"xmlns:vssd", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData";
"xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance";
"xmlns:ovf", "http://schemas.dmtf.org/ovf/envelope/1/";
+ "xmlns:ovirt", "http://www.ovirt.org/ovf";
"ovf:version", "0.9"
] [
Comment generated_by;
@@ -383,8 +581,10 @@ let rec create_ovf source targets guestcaps inspect
] in
(match ovf_flavour with
| OVirt ->
+ let ovirt_osid = get_ovirt_osid inspect in
e "OperatingSystemSection" ["ovf:id", vm_uuid;
- "ovf:required", "false"]
+ "ovf:required", "false";
+ "ovirt:id", string_of_int ovirt_osid]
osinfo_subnodes
| RHVExportStorageDomain ->
e "Section" ["ovf:id", vm_uuid; "ovf:required", "false";
--
2.21.0

View File

@ -1,32 +0,0 @@
From b96a2119b20f204661fa2165aea3c6c2b84e23de Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Thu, 5 Apr 2018 10:28:17 +0200
Subject: [PATCH] v2v: OVF: fix ovf:id for VirtualSystem in OVirt flavour
When writing the OVF in OVirt flavour, write the actual UUID of the
VM as ovf:id attribute for <VirtualSystem>, instead of a dummy value.
Suggested by Arik Hadas in
https://www.redhat.com/archives/libguestfs/2018-April/msg00005.html
(cherry picked from commit 9dce43931a19510be1b6d21ce67d14a4136ce241)
---
v2v/create_ovf.ml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/v2v/create_ovf.ml b/v2v/create_ovf.ml
index 730ab64b4..b1ab8df3f 100644
--- a/v2v/create_ovf.ml
+++ b/v2v/create_ovf.ml
@@ -688,7 +688,7 @@ let rec create_ovf source targets guestcaps inspect
(match ovf_flavour with
| OVirt ->
- e "VirtualSystem" ["ovf:id", "out"] !content_subnodes
+ e "VirtualSystem" ["ovf:id", vm_uuid] !content_subnodes
| RHVExportStorageDomain ->
e "Content" ["ovf:id", "out"; "xsi:type", "ovf:VirtualSystem_Type"]
!content_subnodes
--
2.21.0

View File

@ -0,0 +1,45 @@
From 042554182bcc782527dc74e035e2efaf6eb38aa4 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Mon, 8 Apr 2019 18:23:27 +0200
Subject: [PATCH] v2v: start reading the new libvirt firmware autoselect
Starting with 5.2.0, libvirt has a way to select automatically the
firmware for a guest using an attribute of the <os> tag. Hence, use
this information (when available, of course) to flag the firmware used
by the guest.
(cherry picked from commit fb7983f999004c1f8100776819ea65b21990956d)
---
v2v/parse_libvirt_xml.ml | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/v2v/parse_libvirt_xml.ml b/v2v/parse_libvirt_xml.ml
index b9970cee8..14cd82afd 100644
--- a/v2v/parse_libvirt_xml.ml
+++ b/v2v/parse_libvirt_xml.ml
@@ -476,6 +476,13 @@ let parse_libvirt_xml ?conn xml =
done;
List.rev !nics in
+ (* Firmware. *)
+ let firmware =
+ match xpath_string "/domain/os/@firmware" with
+ | Some "bios" -> BIOS
+ | Some "efi" -> UEFI
+ | None | Some _ -> UnknownFirmware in
+
(* Check for hostdev devices. (RHBZ#1472719) *)
let () =
let obj = Xml.xpath_eval_expression xpathctx "/domain/devices/hostdev" in
@@ -520,7 +527,7 @@ let parse_libvirt_xml ?conn xml =
s_cpu_model = cpu_model;
s_cpu_topology = cpu_topology;
s_features = features;
- s_firmware = UnknownFirmware; (* XXX until RHBZ#1217444 is fixed *)
+ s_firmware = firmware;
s_display = display;
s_video = video;
s_sound = sound;
--
2.26.2

View File

@ -0,0 +1,96 @@
From 692a752cf3e552790ada8cc07f937036adaa8bf0 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Thu, 21 Mar 2019 17:16:37 +0100
Subject: [PATCH] common/mltools: move the code for machine readable up
Move the code for handling machine readable up in the file, so it can be
used by other functions.
Only code motion, no behaviour changes.
(cherry picked from commit 8b06ea0ebc9534e4fda9cc9a33c98f939401af79)
---
common/mltools/tools_utils.ml | 60 +++++++++++++++++------------------
1 file changed, 30 insertions(+), 30 deletions(-)
diff --git a/common/mltools/tools_utils.ml b/common/mltools/tools_utils.ml
index 24641369e..5a35708cd 100644
--- a/common/mltools/tools_utils.ml
+++ b/common/mltools/tools_utils.ml
@@ -33,6 +33,36 @@ external c_inspect_decrypt : Guestfs.t -> int64 -> (string * key_store_key) list
external c_set_echo_keys : unit -> unit = "guestfs_int_mllib_set_echo_keys" "noalloc"
external c_set_keys_from_stdin : unit -> unit = "guestfs_int_mllib_set_keys_from_stdin" "noalloc"
+type machine_readable_fn = {
+ pr : 'a. ('a, unit, string, unit) format4 -> 'a;
+} (* [@@unboxed] *)
+
+type machine_readable_output_type =
+ | NoOutput
+ | Channel of out_channel
+ | File of string
+let machine_readable_output = ref NoOutput
+let machine_readable_channel = ref None
+let machine_readable () =
+ let chan =
+ if !machine_readable_channel = None then (
+ let chan =
+ match !machine_readable_output with
+ | NoOutput -> None
+ | Channel chan -> Some chan
+ | File f -> Some (open_out f) in
+ machine_readable_channel := chan
+ );
+ !machine_readable_channel
+ in
+ match chan with
+ | None -> None
+ | Some chan ->
+ let pr fs =
+ ksprintf (output_string chan) fs
+ in
+ Some { pr }
+
(* ANSI terminal colours. *)
let istty chan =
Unix.isatty (Unix.descr_of_out_channel chan)
@@ -236,36 +266,6 @@ let human_size i =
)
)
-type machine_readable_fn = {
- pr : 'a. ('a, unit, string, unit) format4 -> 'a;
-} (* [@@unboxed] *)
-
-type machine_readable_output_type =
- | NoOutput
- | Channel of out_channel
- | File of string
-let machine_readable_output = ref NoOutput
-let machine_readable_channel = ref None
-let machine_readable () =
- let chan =
- if !machine_readable_channel = None then (
- let chan =
- match !machine_readable_output with
- | NoOutput -> None
- | Channel chan -> Some chan
- | File f -> Some (open_out f) in
- machine_readable_channel := chan
- );
- !machine_readable_channel
- in
- match chan with
- | None -> None
- | Some chan ->
- let pr fs =
- ksprintf (output_string chan) fs
- in
- Some { pr }
-
type cmdline_options = {
getopt : Getopt.t;
ks : key_store;
--
2.26.2

View File

@ -0,0 +1,34 @@
From 61e503d193706c38d58147a2d308faf01948550c Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Fri, 22 Mar 2019 11:36:41 +0100
Subject: [PATCH] common/mltools: make sure machine readable output is flushed
Enhance the helper printf function for machine readable output to always
flush after each string: this way, readers of the machine readable
stream can get the output as soon as it is outputted.
(cherry picked from commit abf1607f46ddc3d829a3688b9499a9bcd2319d19)
---
common/mltools/tools_utils.ml | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/common/mltools/tools_utils.ml b/common/mltools/tools_utils.ml
index 5a35708cd..ade4cb37f 100644
--- a/common/mltools/tools_utils.ml
+++ b/common/mltools/tools_utils.ml
@@ -59,7 +59,11 @@ let machine_readable () =
| None -> None
| Some chan ->
let pr fs =
- ksprintf (output_string chan) fs
+ let out s =
+ output_string chan s;
+ flush chan
+ in
+ ksprintf out fs
in
Some { pr }
--
2.26.2

View File

@ -1,28 +0,0 @@
From 2648e807faaa94c080c33b8a0d70c078339c59f8 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Fri, 20 Apr 2018 13:00:56 +0200
Subject: [PATCH] v2v: refer to the right embed script in EXTRA_DIST
Fixes commit cc04573927cca97de60d544d37467e67c25867a7.
(cherry picked from commit cf49fe100338aeac281c7cbcdfe743177ceb0606)
---
v2v/Makefile.am | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/v2v/Makefile.am b/v2v/Makefile.am
index 694a64573..3a0c80f44 100644
--- a/v2v/Makefile.am
+++ b/v2v/Makefile.am
@@ -31,7 +31,7 @@ EXTRA_DIST = \
$(SOURCES_MLI) $(SOURCES_ML) $(SOURCES_C) \
copy_to_local.ml \
copy_to_local.mli \
- embed-code.sh \
+ embed.sh \
rhv-upload-createvm.py \
rhv-upload-plugin.py \
rhv-upload-precheck.py \
--
2.21.0

View File

@ -0,0 +1,87 @@
From 0dd5c55c62f4e239c7be75852cf8a667be833cf1 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Fri, 22 Mar 2019 12:59:11 +0100
Subject: [PATCH] common/mltools: allow fd for machine readable output
Allow to specify a file descriptor for the machine readable output.
Use the same assumption as done in v2v, i.e. that Unix.file_descr is
simply the int file descriptor.
(cherry picked from commit 70514dfaf1e45b5ad34f20f3297af9782099cf80)
---
common/mltools/test-machine-readable.sh | 7 +++++++
common/mltools/tools_utils.ml | 11 ++++++++++-
lib/guestfs.pod | 5 +++++
3 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/common/mltools/test-machine-readable.sh b/common/mltools/test-machine-readable.sh
index 1162c58e9..824460e6d 100755
--- a/common/mltools/test-machine-readable.sh
+++ b/common/mltools/test-machine-readable.sh
@@ -65,3 +65,10 @@ test $($t --machine-readable=stream:stdout |& wc -l) -eq 3
# Output "stream:stderr".
$t --machine-readable=stream:stderr 2>&1 >/dev/null | grep 'machine-readable'
test $($t --machine-readable=stream:stderr 2>&1 >/dev/null | wc -l) -eq 2
+
+# Output "fd:".
+fn="$tmpdir/fdfile"
+exec 4>"$fn"
+$t --machine-readable=fd:4
+exec 4>&-
+test $(cat "$fn" | wc -l) -eq 1
diff --git a/common/mltools/tools_utils.ml b/common/mltools/tools_utils.ml
index ade4cb37f..35478f39e 100644
--- a/common/mltools/tools_utils.ml
+++ b/common/mltools/tools_utils.ml
@@ -41,6 +41,7 @@ type machine_readable_output_type =
| NoOutput
| Channel of out_channel
| File of string
+ | Fd of int
let machine_readable_output = ref NoOutput
let machine_readable_channel = ref None
let machine_readable () =
@@ -50,7 +51,10 @@ let machine_readable () =
match !machine_readable_output with
| NoOutput -> None
| Channel chan -> Some chan
- | File f -> Some (open_out f) in
+ | File f -> Some (open_out f)
+ | Fd fd ->
+ (* Note that Unix.file_descr is really just an int. *)
+ Some (Unix.out_channel_of_descr (Obj.magic fd)) in
machine_readable_channel := chan
);
!machine_readable_channel
@@ -296,6 +300,11 @@ let create_standard_options argspec ?anon_fun ?(key_opts = false) ?(machine_read
| n ->
error (f_"invalid output stream for --machine-readable: %s") fmt in
machine_readable_output := Channel chan
+ | "fd" ->
+ (try
+ machine_readable_output := Fd (int_of_string outname)
+ with Failure _ ->
+ error (f_"invalid output fd for --machine-readable: %s") fmt)
| n ->
error (f_"invalid output for --machine-readable: %s") fmt
)
diff --git a/lib/guestfs.pod b/lib/guestfs.pod
index 53cece2da..f11028466 100644
--- a/lib/guestfs.pod
+++ b/lib/guestfs.pod
@@ -3287,6 +3287,11 @@ The possible values are:
=over 4
+=item B<fd:>I<fd>
+
+The output goes to the specified I<fd>, which is a file descriptor
+already opened for writing.
+
=item B<file:>F<filename>
The output goes to the specified F<filename>.
--
2.26.2

View File

@ -1,84 +0,0 @@
From 2e9cc6b2307668f330d11384bba63b70160d3e42 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Fri, 20 Apr 2018 11:48:47 +0100
Subject: [PATCH] =?UTF-8?q?v2v:=20-o=20rhv-upload:=20Don't=20require=20?=
=?UTF-8?q?=E2=80=98-of=20raw=E2=80=99=20parameter.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Because we checked the limitation of raw+sparse during command line
processing, it had the effect of forcing you to use -of raw even if
the input was already in raw format. Move the checking to the output
mode to avoid this.
Fixes commit cc04573927cca97de60d544d37467e67c25867a7.
(cherry picked from commit b3769afaece360b8a2095e3d8a7a934d351c3ade)
---
v2v/cmdline.ml | 5 -----
v2v/output_rhv_upload.ml | 18 +++++++++++++++++-
2 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
index 9b1348c37..97d4f4377 100644
--- a/v2v/cmdline.ml
+++ b/v2v/cmdline.ml
@@ -586,11 +586,6 @@ read the man page virt-v2v(1).
| None ->
error (f_"-o rhv-upload: use -oc to point to the oVirt or RHV server REST API URL, which is usually https://servername/ovirt-engine/api")
| Some oc -> oc in
- (* Output format / sparse must currently be raw+sparse. We can
- * change this in future. See TODO file for details. XXX
- *)
- if output_alloc <> Sparse || output_format <> Some "raw" then
- error (f_"-o rhv-upload: currently you must use -of raw and you cannot use -oa preallocated with this output mode. These restrictions will be loosened in a future version.");
(* In theory we could make the password optional in future. *)
let output_password =
match output_password with
diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml
index 129461242..dc0d96d53 100644
--- a/v2v/output_rhv_upload.ml
+++ b/v2v/output_rhv_upload.ml
@@ -169,6 +169,19 @@ See also \"OUTPUT TO RHV\" in the virt-v2v(1) manual.")
error (f_"nbdkit was compiled without SELinux support. You will have to recompile nbdkit with libselinux-devel installed, or else set SELinux to Permissive mode while doing the conversion.")
in
+ (* Output format/sparse must be raw/sparse. We may be able to
+ * lift this limitation in future, but it requires changes on the
+ * RHV side. See TODO file for details. XXX
+ *)
+ let error_current_limitation required_param =
+ error (f_"rhv-upload: currently you must use %s. This restriction will be loosened in a future version.") required_param
+ in
+
+ let error_unless_output_alloc_sparse () =
+ if output_alloc <> Sparse then
+ error_current_limitation "-oa sparse"
+ in
+
(* JSON parameters which are invariant between disks. *)
let json_params = [
"verbose", JSON.Bool (verbose ());
@@ -220,6 +233,7 @@ object
error_unless_python_binary_on_path ();
error_unless_nbdkit_working ();
error_unless_nbdkit_python3_working ();
+ error_unless_output_alloc_sparse ();
if have_selinux then
error_unless_nbdkit_compiled_with_selinux ()
@@ -260,7 +274,9 @@ object
let disk_format =
match t.target_format with
- | ("raw" | "qcow2") as fmt -> fmt
+ | "raw" as fmt -> fmt
+ | "qcow2" ->
+ error_current_limitation "-of raw"
| _ ->
error (f_"rhv-upload: -of %s: Only output format raw or qcow2 is supported. If the input is in a different format then force one of these output formats by adding either -of raw or -of qcow2 on the command line.")
t.target_format in
--
2.21.0

View File

@ -0,0 +1,514 @@
From 1b29702cefae8a66c83bc84dd15e7b858af3ab47 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Fri, 22 Mar 2019 16:24:25 +0100
Subject: [PATCH] OCaml tools: output messages into JSON for machine readable
When the machine readable mode is enabled, print all the messages
(progress, info, warning, and errors) also as JSON in the machine
readable stream: this way, users can easily parse the status of the
OCaml tool, and report that back.
The formatting of the current date time into the RFC 3999 format is done
in C, because of the lack of OCaml APIs for this.
(cherry picked from commit f79129b8dc92470e3a5597daf53c84038bd6859e)
---
.gitignore | 1 +
common/mltools/Makefile.am | 39 ++++++-
common/mltools/parse_tools_messages_test.py | 118 ++++++++++++++++++++
common/mltools/test-tools-messages.sh | 28 +++++
common/mltools/tools_messages_tests.ml | 46 ++++++++
common/mltools/tools_utils-c.c | 51 +++++++++
common/mltools/tools_utils.ml | 16 +++
lib/guestfs.pod | 19 ++++
8 files changed, 316 insertions(+), 2 deletions(-)
create mode 100644 common/mltools/parse_tools_messages_test.py
create mode 100755 common/mltools/test-tools-messages.sh
create mode 100644 common/mltools/tools_messages_tests.ml
diff --git a/.gitignore b/.gitignore
index f2efcdde2..db1dbb7cc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -147,6 +147,7 @@ Makefile.in
/common/mltools/JSON_tests
/common/mltools/JSON_parser_tests
/common/mltools/machine_readable_tests
+/common/mltools/tools_messages_tests
/common/mltools/tools_utils_tests
/common/mltools/oUnit-*
/common/mlutils/.depend
diff --git a/common/mltools/Makefile.am b/common/mltools/Makefile.am
index 37d10e610..ae78b84b7 100644
--- a/common/mltools/Makefile.am
+++ b/common/mltools/Makefile.am
@@ -27,6 +27,8 @@ EXTRA_DIST = \
machine_readable_tests.ml \
test-getopt.sh \
test-machine-readable.sh \
+ test-tools-messages.sh \
+ tools_messages_tests.ml \
tools_utils_tests.ml
SOURCES_MLI = \
@@ -45,12 +47,12 @@ SOURCES_MLI = \
SOURCES_ML = \
getopt.ml \
+ JSON.ml \
tools_utils.ml \
URI.ml \
planner.ml \
registry.ml \
regedit.ml \
- JSON.ml \
JSON_parser.ml \
curl.ml \
checksums.ml \
@@ -196,6 +198,15 @@ machine_readable_tests_CPPFLAGS = \
machine_readable_tests_BOBJECTS = machine_readable_tests.cmo
machine_readable_tests_XOBJECTS = $(machine_readable_tests_BOBJECTS:.cmo=.cmx)
+tools_messages_tests_SOURCES = dummy.c
+tools_messages_tests_CPPFLAGS = \
+ -I. \
+ -I$(top_builddir) \
+ -I$(shell $(OCAMLC) -where) \
+ -I$(top_srcdir)/lib
+tools_messages_tests_BOBJECTS = tools_messages_tests.cmo
+tools_messages_tests_XOBJECTS = $(tools_messages_tests_BOBJECTS:.cmo=.cmx)
+
# Can't call the following as <test>_OBJECTS because automake gets confused.
if !HAVE_OCAMLOPT
tools_utils_tests_THEOBJECTS = $(tools_utils_tests_BOBJECTS)
@@ -212,6 +223,9 @@ JSON_parser_tests.cmo: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
machine_readable_tests_THEOBJECTS = $(machine_readable_tests_BOBJECTS)
machine_readable_tests.cmo: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
+
+tools_messages_tests_THEOBJECTS = $(tools_messages_tests_tests_BOBJECTS)
+tools_messages_tests.cmo: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
else
tools_utils_tests_THEOBJECTS = $(tools_utils_tests_XOBJECTS)
tools_utils_tests.cmx: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
@@ -227,6 +241,9 @@ JSON_parser_tests.cmx: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
machine_readable_tests_THEOBJECTS = $(machine_readable_tests_XOBJECTS)
machine_readable_tests.cmx: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
+
+tools_messages_tests_THEOBJECTS = $(tools_messages_tests_XOBJECTS)
+tools_messages_tests.cmx: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
endif
OCAMLLINKFLAGS = \
@@ -302,14 +319,32 @@ machine_readable_tests_LINK = \
$(OCAMLPACKAGES) $(OCAMLPACKAGES_TESTS) \
$(machine_readable_tests_THEOBJECTS) -o $@
+tools_messages_tests_DEPENDENCIES = \
+ $(tools_messages_tests_THEOBJECTS) \
+ ../mlstdutils/mlstdutils.$(MLARCHIVE) \
+ ../mlgettext/mlgettext.$(MLARCHIVE) \
+ ../mlpcre/mlpcre.$(MLARCHIVE) \
+ $(MLTOOLS_CMA) \
+ $(top_srcdir)/ocaml-link.sh
+tools_messages_tests_LINK = \
+ $(top_srcdir)/ocaml-link.sh -cclib '-lutils -lgnu' -- \
+ $(OCAMLFIND) $(BEST) $(OCAMLFLAGS) $(OCAMLLINKFLAGS) \
+ $(OCAMLPACKAGES) $(OCAMLPACKAGES_TESTS) \
+ $(tools_messages_tests_THEOBJECTS) -o $@
+
TESTS_ENVIRONMENT = $(top_builddir)/run --test
TESTS = \
test-getopt.sh \
test-machine-readable.sh
+if HAVE_PYTHON
+TESTS += \
+ test-tools-messages.sh
+endif
check_PROGRAMS = \
getopt_tests \
- machine_readable_tests
+ machine_readable_tests \
+ tools_messages_tests
if HAVE_OCAML_PKG_OUNIT
check_PROGRAMS += JSON_tests JSON_parser_tests tools_utils_tests
diff --git a/common/mltools/parse_tools_messages_test.py b/common/mltools/parse_tools_messages_test.py
new file mode 100644
index 000000000..9dcd6cae6
--- /dev/null
+++ b/common/mltools/parse_tools_messages_test.py
@@ -0,0 +1,118 @@
+# Copyright (C) 2019 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import datetime
+import json
+import os
+import sys
+import unittest
+
+exe = "tools_messages_tests"
+
+if sys.version_info >= (3, 4):
+ def set_fd_inheritable(fd):
+ os.set_inheritable(fd, True)
+else:
+ def set_fd_inheritable(fd):
+ pass
+
+
+if sys.version_info >= (3, 0):
+ def fdopen(fd, mode):
+ return open(fd, mode)
+
+ def isModuleInstalled(mod):
+ import importlib
+ return bool(importlib.util.find_spec(mod))
+else:
+ def fdopen(fd, mode):
+ return os.fdopen(fd, mode)
+
+ def isModuleInstalled(mod):
+ import imp
+ try:
+ imp.find_module(mod)
+ return True
+ except ImportError:
+ return False
+
+
+def skipUnlessHasModule(mod):
+ if not isModuleInstalled(mod):
+ return unittest.skip("%s not available" % mod)
+ return lambda func: func
+
+
+def iterload(stream):
+ dec = json.JSONDecoder()
+ for line in stream:
+ yield dec.raw_decode(line)
+
+
+def loadJsonFromCommand(extraargs):
+ r, w = os.pipe()
+ set_fd_inheritable(r)
+ r = fdopen(r, "r")
+ set_fd_inheritable(w)
+ w = fdopen(w, "w")
+ pid = os.fork()
+ if pid:
+ w.close()
+ l = list(iterload(r))
+ l = [o[0] for o in l]
+ r.close()
+ return l
+ else:
+ r.close()
+ args = ["tools_messages_tests",
+ "--machine-readable=fd:%d" % w.fileno()] + extraargs
+ os.execvp("./" + exe, args)
+
+
+@skipUnlessHasModule('iso8601')
+class TestParseToolsMessages(unittest.TestCase):
+ def check_json(self, json, typ, msg):
+ import iso8601
+ # Check the type.
+ jsontype = json.pop("type")
+ self.assertEqual(jsontype, typ)
+ # Check the message.
+ jsonmsg = json.pop("message")
+ self.assertEqual(jsonmsg, msg)
+ # Check the timestamp.
+ jsonts = json.pop("timestamp")
+ dt = iso8601.parse_date(jsonts)
+ now = datetime.datetime.now(dt.tzinfo)
+ self.assertGreater(now, dt)
+ # Check there are no more keys left (and thus not previously tested).
+ self.assertEqual(len(json), 0)
+
+ def test_messages(self):
+ objects = loadJsonFromCommand([])
+ self.assertEqual(len(objects), 4)
+ self.check_json(objects[0], "message", "Starting")
+ self.check_json(objects[1], "info", "An information message")
+ self.check_json(objects[2], "warning", "Warning: message here")
+ self.check_json(objects[3], "message", "Finishing")
+
+ def test_error(self):
+ objects = loadJsonFromCommand(["--error"])
+ self.assertEqual(len(objects), 1)
+ self.check_json(objects[0], "error", "Error!")
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/common/mltools/test-tools-messages.sh b/common/mltools/test-tools-messages.sh
new file mode 100755
index 000000000..0e24d6ce9
--- /dev/null
+++ b/common/mltools/test-tools-messages.sh
@@ -0,0 +1,28 @@
+#!/bin/bash -
+# libguestfs
+# Copyright (C) 2019 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Test the --machine-readable functionality of the module Tools_utils.
+# See also: machine_readable_tests.ml
+
+set -e
+set -x
+
+$TEST_FUNCTIONS
+skip_if_skipped
+
+$PYTHON parse_tools_messages_test.py
diff --git a/common/mltools/tools_messages_tests.ml b/common/mltools/tools_messages_tests.ml
new file mode 100644
index 000000000..d5f9be89b
--- /dev/null
+++ b/common/mltools/tools_messages_tests.ml
@@ -0,0 +1,46 @@
+(*
+ * Copyright (C) 2019 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+(* Test the message output for tools of the module Tools_utils.
+ * The tests are controlled by the test-tools-messages.sh script.
+ *)
+
+open Printf
+
+open Std_utils
+open Tools_utils
+open Getopt.OptionName
+
+let is_error = ref false
+
+let args = [
+ [ L "error" ], Getopt.Set is_error, "Only print the error";
+]
+let usage_msg = sprintf "%s: test the message outputs" prog
+
+let opthandle = create_standard_options args ~machine_readable:true usage_msg
+let () =
+ Getopt.parse opthandle.getopt;
+
+ if !is_error then
+ error "Error!";
+
+ message "Starting";
+ info "An information message";
+ warning "Warning: message here";
+ message "Finishing"
diff --git a/common/mltools/tools_utils-c.c b/common/mltools/tools_utils-c.c
index c88c95082..b015dcace 100644
--- a/common/mltools/tools_utils-c.c
+++ b/common/mltools/tools_utils-c.c
@@ -23,6 +23,8 @@
#include <unistd.h>
#include <errno.h>
#include <error.h>
+#include <time.h>
+#include <string.h>
#include <caml/alloc.h>
#include <caml/fail.h>
@@ -37,6 +39,7 @@
extern value guestfs_int_mllib_inspect_decrypt (value gv, value gpv, value keysv);
extern value guestfs_int_mllib_set_echo_keys (value unitv);
extern value guestfs_int_mllib_set_keys_from_stdin (value unitv);
+extern value guestfs_int_mllib_rfc3999_date_time_string (value unitv);
/* Interface with the guestfish inspection and decryption code. */
int echo_keys = 0;
@@ -103,3 +106,51 @@ guestfs_int_mllib_set_keys_from_stdin (value unitv)
keys_from_stdin = 1;
return Val_unit;
}
+
+value
+guestfs_int_mllib_rfc3999_date_time_string (value unitv)
+{
+ CAMLparam1 (unitv);
+ char buf[64];
+ struct timespec ts;
+ struct tm tm;
+ size_t ret;
+ size_t total = 0;
+
+ if (clock_gettime (CLOCK_REALTIME, &ts) == -1)
+ unix_error (errno, (char *) "clock_gettime", Val_unit);
+
+ if (localtime_r (&ts.tv_sec, &tm) == NULL)
+ unix_error (errno, (char *) "localtime_r", caml_copy_int64 (ts.tv_sec));
+
+ /* Sadly strftime does not support nanoseconds, so what we do is:
+ * - stringify everything before the nanoseconds
+ * - print the nanoseconds
+ * - stringify the rest (i.e. the timezone)
+ * then place ':' between the hours, and the minutes of the
+ * timezone offset.
+ */
+
+ ret = strftime (buf, sizeof (buf), "%Y-%m-%dT%H:%M:%S.", &tm);
+ if (ret == 0)
+ unix_error (errno, (char *) "strftime", Val_unit);
+ total += ret;
+
+ ret = snprintf (buf + total, sizeof (buf) - total, "%09ld", ts.tv_nsec);
+ if (ret == 0)
+ unix_error (errno, (char *) "sprintf", caml_copy_int64 (ts.tv_nsec));
+ total += ret;
+
+ ret = strftime (buf + total, sizeof (buf) - total, "%z", &tm);
+ if (ret == 0)
+ unix_error (errno, (char *) "strftime", Val_unit);
+ total += ret;
+
+ /* Move the timezone minutes one character to the right, moving the
+ * null character too.
+ */
+ memmove (buf + total - 1, buf + total - 2, 3);
+ buf[total - 2] = ':';
+
+ CAMLreturn (caml_copy_string (buf));
+}
diff --git a/common/mltools/tools_utils.ml b/common/mltools/tools_utils.ml
index 35478f39e..de42df600 100644
--- a/common/mltools/tools_utils.ml
+++ b/common/mltools/tools_utils.ml
@@ -32,6 +32,7 @@ and key_store_key =
external c_inspect_decrypt : Guestfs.t -> int64 -> (string * key_store_key) list -> unit = "guestfs_int_mllib_inspect_decrypt"
external c_set_echo_keys : unit -> unit = "guestfs_int_mllib_set_echo_keys" "noalloc"
external c_set_keys_from_stdin : unit -> unit = "guestfs_int_mllib_set_keys_from_stdin" "noalloc"
+external c_rfc3999_date_time_string : unit -> string = "guestfs_int_mllib_rfc3999_date_time_string"
type machine_readable_fn = {
pr : 'a. ('a, unit, string, unit) format4 -> 'a;
@@ -86,12 +87,24 @@ let ansi_magenta ?(chan = stdout) () =
let ansi_restore ?(chan = stdout) () =
if colours () || istty chan then output_string chan "\x1b[0m"
+let log_as_json msgtype msg =
+ match machine_readable () with
+ | None -> ()
+ | Some { pr } ->
+ let json = [
+ "message", JSON.String msg;
+ "timestamp", JSON.String (c_rfc3999_date_time_string ());
+ "type", JSON.String msgtype;
+ ] in
+ pr "%s\n" (JSON.string_of_doc ~fmt:JSON.Compact json)
+
(* Timestamped progress messages, used for ordinary messages when not
* --quiet.
*)
let start_t = Unix.gettimeofday ()
let message fs =
let display str =
+ log_as_json "message" str;
if not (quiet ()) then (
let t = sprintf "%.1f" (Unix.gettimeofday () -. start_t) in
printf "[%6s] " t;
@@ -106,6 +119,7 @@ let message fs =
(* Error messages etc. *)
let error ?(exit_code = 1) fs =
let display str =
+ log_as_json "error" str;
let chan = stderr in
ansi_red ~chan ();
wrap ~chan (sprintf (f_"%s: error: %s") prog str);
@@ -124,6 +138,7 @@ let error ?(exit_code = 1) fs =
let warning fs =
let display str =
+ log_as_json "warning" str;
let chan = stdout in
ansi_blue ~chan ();
wrap ~chan (sprintf (f_"%s: warning: %s") prog str);
@@ -134,6 +149,7 @@ let warning fs =
let info fs =
let display str =
+ log_as_json "info" str;
let chan = stdout in
ansi_magenta ~chan ();
wrap ~chan (sprintf (f_"%s: %s") prog str);
diff --git a/lib/guestfs.pod b/lib/guestfs.pod
index f11028466..3c1d635c5 100644
--- a/lib/guestfs.pod
+++ b/lib/guestfs.pod
@@ -3279,6 +3279,25 @@ Some of the tools support a I<--machine-readable> option, which is
generally used to make the output more machine friendly, for easier
parsing for example. By default, this output goes to stdout.
+When using the I<--machine-readable> option, the progress,
+information, warning, and error messages are also printed in JSON
+format for easier log tracking. Thus, it is highly recommended to
+redirect the machine-readable output to a different stream. The
+format of these JSON messages is like the following (actually printed
+within a single line, below it is indented for readability):
+
+ {
+ "message": "Finishing off",
+ "timestamp": "2019-03-22T14:46:49.067294446+01:00",
+ "type": "message"
+ }
+
+C<type> can be: C<message> for progress messages, C<info> for
+information messages, C<warning> for warning messages, and C<error>
+for error message.
+C<timestamp> is the L<RFC 3999|https://www.ietf.org/rfc/rfc3339.txt>
+timestamp of the message.
+
In addition to that, a subset of these tools support an extra string
passed to the I<--machine-readable> option: this string specifies
where the machine-readable output will go.
--
2.26.2

View File

@ -1,31 +0,0 @@
From 1ddbe89dbc3877e6135e13413f97ee30a12c8e72 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Golembiovsk=C3=BD?= <tgolembi@redhat.com>
Date: Sun, 22 Apr 2018 22:57:55 +0200
Subject: [PATCH] v2v: -o rhv-upload: install RHV tools (RHBZ#1561828).
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Tomáš Golembiovský <tgolembi@redhat.com>
(cherry picked from commit f3f00d3f9c6464aa31e3091bdee1191ef15512c6)
---
v2v/output_rhv_upload.ml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml
index dc0d96d53..0152b8d5a 100644
--- a/v2v/output_rhv_upload.ml
+++ b/v2v/output_rhv_upload.ml
@@ -247,6 +247,9 @@ object
method supported_firmware = [ TargetBIOS ]
+ (* rhev-apt.exe will be installed (if available). *)
+ method install_rhev_apt = true
+
method prepare_targets source targets =
let output_name = source.s_name in
let json_params =
--
2.21.0

View File

@ -0,0 +1,77 @@
From 1d4e167ebcf75771957f3ba109354a8217e78004 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Mon, 1 Apr 2019 17:01:44 +0200
Subject: [PATCH] OCaml tools: fix 3999 -> 3339 typo
RFC 3339 is the actual RFC for date/time strings.
Typo found by Martin 'eagle eyes' Kletzander.
Fixes commit f79129b8dc92470e3a5597daf53c84038bd6859e.
(cherry picked from commit 1086599ad8eeb8be299d5ffbcb2efb1024ff9ab8)
---
common/mltools/tools_utils-c.c | 4 ++--
common/mltools/tools_utils.ml | 4 ++--
lib/guestfs.pod | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/common/mltools/tools_utils-c.c b/common/mltools/tools_utils-c.c
index b015dcace..3b80091c0 100644
--- a/common/mltools/tools_utils-c.c
+++ b/common/mltools/tools_utils-c.c
@@ -39,7 +39,7 @@
extern value guestfs_int_mllib_inspect_decrypt (value gv, value gpv, value keysv);
extern value guestfs_int_mllib_set_echo_keys (value unitv);
extern value guestfs_int_mllib_set_keys_from_stdin (value unitv);
-extern value guestfs_int_mllib_rfc3999_date_time_string (value unitv);
+extern value guestfs_int_mllib_rfc3339_date_time_string (value unitv);
/* Interface with the guestfish inspection and decryption code. */
int echo_keys = 0;
@@ -108,7 +108,7 @@ guestfs_int_mllib_set_keys_from_stdin (value unitv)
}
value
-guestfs_int_mllib_rfc3999_date_time_string (value unitv)
+guestfs_int_mllib_rfc3339_date_time_string (value unitv)
{
CAMLparam1 (unitv);
char buf[64];
diff --git a/common/mltools/tools_utils.ml b/common/mltools/tools_utils.ml
index de42df600..127180225 100644
--- a/common/mltools/tools_utils.ml
+++ b/common/mltools/tools_utils.ml
@@ -32,7 +32,7 @@ and key_store_key =
external c_inspect_decrypt : Guestfs.t -> int64 -> (string * key_store_key) list -> unit = "guestfs_int_mllib_inspect_decrypt"
external c_set_echo_keys : unit -> unit = "guestfs_int_mllib_set_echo_keys" "noalloc"
external c_set_keys_from_stdin : unit -> unit = "guestfs_int_mllib_set_keys_from_stdin" "noalloc"
-external c_rfc3999_date_time_string : unit -> string = "guestfs_int_mllib_rfc3999_date_time_string"
+external c_rfc3339_date_time_string : unit -> string = "guestfs_int_mllib_rfc3339_date_time_string"
type machine_readable_fn = {
pr : 'a. ('a, unit, string, unit) format4 -> 'a;
@@ -93,7 +93,7 @@ let log_as_json msgtype msg =
| Some { pr } ->
let json = [
"message", JSON.String msg;
- "timestamp", JSON.String (c_rfc3999_date_time_string ());
+ "timestamp", JSON.String (c_rfc3339_date_time_string ());
"type", JSON.String msgtype;
] in
pr "%s\n" (JSON.string_of_doc ~fmt:JSON.Compact json)
diff --git a/lib/guestfs.pod b/lib/guestfs.pod
index 3c1d635c5..af944ddb7 100644
--- a/lib/guestfs.pod
+++ b/lib/guestfs.pod
@@ -3295,7 +3295,7 @@ within a single line, below it is indented for readability):
C<type> can be: C<message> for progress messages, C<info> for
information messages, C<warning> for warning messages, and C<error>
for error message.
-C<timestamp> is the L<RFC 3999|https://www.ietf.org/rfc/rfc3339.txt>
+C<timestamp> is the L<RFC 3339|https://www.ietf.org/rfc/rfc3339.txt>
timestamp of the message.
In addition to that, a subset of these tools support an extra string
--
2.26.2

View File

@ -1,30 +0,0 @@
From c2570c81e8c3dffadbcfa5c857a38ae858745f9e Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 1 May 2018 11:30:11 +0100
Subject: [PATCH] v2v: Map Windows Server 2012 R2 x86-64 to ovirt ID 25.
Thanks: Michal Skrivanek
Fixes commit 593a19cc86cfa8f24c66518c8ba21222550b066a.
(cherry picked from commit c6e89299299f1f620437ac3d05a1f0f12de0f208)
---
v2v/create_ovf.ml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/v2v/create_ovf.ml b/v2v/create_ovf.ml
index b1ab8df3f..b3beb1eba 100644
--- a/v2v/create_ovf.ml
+++ b/v2v/create_ovf.ml
@@ -418,7 +418,7 @@ and get_ovirt_osid = function
| { i_type = "windows"; i_major_version = 6; i_minor_version = 3;
i_arch = "x86_64" } ->
- 23
+ 25
| { i_type = "windows"; i_major_version = 10; i_minor_version = 0;
i_arch = "i386" } ->
--
2.21.0

View File

@ -1,54 +0,0 @@
From b31fcaf9879b9f4fe36a19e439895a867a1fbc72 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Tue, 22 May 2018 17:24:18 +0200
Subject: [PATCH] v2v: fix build rules for output_rhv_upload_*_source.ml files
Use the $(srcdir) variable where needed, to make sure it builds also
with srcdir != builddir.
Furthermore, make sure that the OCaml dependencies calculation depend on
the generated output_rhv_upload_*_source.ml files, otherwise there will
be incomplete OCaml rules for them in the generated .depend.
Fixes commit cc04573927cca97de60d544d37467e67c25867a7.
(cherry picked from commit a4e3b7c0598370d8d068b21909da95b6031eb688)
---
v2v/Makefile.am | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/v2v/Makefile.am b/v2v/Makefile.am
index 3a0c80f44..7de050b06 100644
--- a/v2v/Makefile.am
+++ b/v2v/Makefile.am
@@ -143,12 +143,12 @@ SOURCES_C = \
# These files are generated and contain rhv-upload-*.py embedded as an
# OCaml string.
-output_rhv_upload_createvm_source.ml: rhv-upload-createvm.py
- ./embed.sh code $^ $@
-output_rhv_upload_plugin_source.ml: rhv-upload-plugin.py
- ./embed.sh code $^ $@
-output_rhv_upload_precheck_source.ml: rhv-upload-precheck.py
- ./embed.sh code $^ $@
+output_rhv_upload_createvm_source.ml: $(srcdir)/rhv-upload-createvm.py
+ $(srcdir)/embed.sh code $^ $@
+output_rhv_upload_plugin_source.ml: $(srcdir)/rhv-upload-plugin.py
+ $(srcdir)/embed.sh code $^ $@
+output_rhv_upload_precheck_source.ml: $(srcdir)/rhv-upload-precheck.py
+ $(srcdir)/embed.sh code $^ $@
if HAVE_OCAML
@@ -575,7 +575,7 @@ v2v_unit_tests_LINK = \
$(v2v_unit_tests_THEOBJECTS) -o $@
# Dependencies.
-.depend: $(srcdir)/*.mli $(srcdir)/*.ml
+.depend: $(srcdir)/*.mli $(srcdir)/*.ml output_rhv_upload_createvm_source.ml output_rhv_upload_plugin_source.ml output_rhv_upload_precheck_source.ml
$(top_builddir)/ocaml-dep.sh $^
-include .depend
--
2.21.0

View File

@ -0,0 +1,31 @@
From 18007f645332e6a7c039a6bdb690e0a55f9cd1c7 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Thu, 18 Jul 2019 15:38:53 +0200
Subject: [PATCH] v2v: remove extra nbdkit bit from documentation
(RHBZ#1723305)
Since there is no more need to build nbdkit from sources, then there is
no need to set $PATH with a custom build of nbdkit.
Followup of commit 0704d8eb0bcc8139886eb4291f75a3ca49a91e58.
(cherry picked from commit 6d251e3828ff94deac7589b5892df174430e01f9)
---
v2v/virt-v2v-input-vmware.pod | 1 -
1 file changed, 1 deletion(-)
diff --git a/v2v/virt-v2v-input-vmware.pod b/v2v/virt-v2v-input-vmware.pod
index b3ebda182..3acdd773e 100644
--- a/v2v/virt-v2v-input-vmware.pod
+++ b/v2v/virt-v2v-input-vmware.pod
@@ -293,7 +293,6 @@ To import a particular guest from vCenter server or ESXi hypervisor,
use a command like the following, substituting the URI, guest name and
SSL thumbprint:
- $ export PATH=/path/to/nbdkit-1.1.x:$PATH
$ virt-v2v \
-ic 'vpx://root@vcenter.example.com/Datacenter/esxi?no_verify=1' \
-it vddk \
--
2.26.2

View File

@ -1,37 +0,0 @@
From bd2afb6e11b107aa7f158136ff6d4fb24732b2bf Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Tue, 29 May 2018 06:49:23 +0200
Subject: [PATCH] v2v: fix "rhevexp" typo in documentation
Spotted by Ming Xie.
(cherry picked from commit c021ac5e64053052a392762aaff9c8ed73fc2082)
---
v2v/virt-v2v.pod | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
index 2d2f8cfd3..f012ea533 100644
--- a/v2v/virt-v2v.pod
+++ b/v2v/virt-v2v.pod
@@ -728,7 +728,7 @@ Currently there are two possible flavours:
=over 4
-=item rhevexp
+=item rhvexp
The OVF format used in RHV export storage domain.
@@ -738,7 +738,7 @@ The OVF format understood by oVirt REST API.
=back
-For backward compatibility the default is I<rhevexp>, but this may change in
+For backward compatibility the default is I<rhvexp>, but this may change in
the future.
=item B<-op> file
--
2.21.0

View File

@ -1,4 +1,4 @@
From 06e5cfb90bc63f1d6c56821f0745c6fa8d3f8259 Mon Sep 17 00:00:00 2001 From d74842f209b5461692a2d283d622157862bdc230 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com> From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Thu, 25 Jul 2019 14:52:42 +0100 Date: Thu, 25 Jul 2019 14:52:42 +0100
Subject: [PATCH] v2v: -i vmx: Use scp -T option if available to unbreak scp Subject: [PATCH] v2v: -i vmx: Use scp -T option if available to unbreak scp
@ -18,7 +18,7 @@ Thanks: Ming Xie, Jakub Jelen.
1 file changed, 7 insertions(+), 1 deletion(-) 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/v2v/input_vmx.ml b/v2v/input_vmx.ml diff --git a/v2v/input_vmx.ml b/v2v/input_vmx.ml
index f79e89139..695266313 100644 index b169b2537..e3469308d 100644
--- a/v2v/input_vmx.ml --- a/v2v/input_vmx.ml
+++ b/v2v/input_vmx.ml +++ b/v2v/input_vmx.ml
@@ -61,6 +61,11 @@ let server_of_uri { Xml.uri_server } = @@ -61,6 +61,11 @@ let server_of_uri { Xml.uri_server } =
@ -45,5 +45,5 @@ index f79e89139..695266313 100644
| None -> "" | None -> ""
| Some port -> sprintf " -P %d" port) | Some port -> sprintf " -P %d" port)
-- --
2.21.0 2.26.2

View File

@ -0,0 +1,28 @@
From 4b94dac532dc17cde462479bf90ab2631006b80b Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Thu, 4 Jul 2019 15:51:25 +0100
Subject: [PATCH] v2v: Allow Windows virtio ISO to be a block device as well as
a regular file.
Thanks: Steven Rosenberg
(cherry picked from commit c22a8b68fe5729d3a8907b41eef287cd9f3a55c0)
---
v2v/windows_virtio.ml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/v2v/windows_virtio.ml b/v2v/windows_virtio.ml
index 92bf3ec60..a6dc29f2c 100644
--- a/v2v/windows_virtio.ml
+++ b/v2v/windows_virtio.ml
@@ -330,7 +330,7 @@ and copy_from_virtio_win g inspect srcdir destdir filter missing =
) paths
)
)
- else if is_regular_file virtio_win then (
+ else if is_regular_file virtio_win || is_block_device virtio_win then (
debug "windows: copy_from_virtio_win: guest tools source ISO %s" virtio_win;
try
--
2.26.2

View File

@ -1,66 +0,0 @@
From 973810a232b2f2a33425d28287e0ec77c483279a Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Tue, 29 May 2018 07:04:50 +0200
Subject: [PATCH] v2v: add and use Create_ovf.ovf_flavour_to_string
Add an helper to convert an OVF flavour to string, and use it in
-o vdsm to print the actual value of the vdsm-ovf-flavour option.
Thanks to Ming Xie.
(cherry picked from commit c0da02f90d9b52413c24dd9dae61662ad033cc16)
---
v2v/create_ovf.ml | 4 ++++
v2v/create_ovf.mli | 3 +++
v2v/output_vdsm.ml | 5 +++--
3 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/v2v/create_ovf.ml b/v2v/create_ovf.ml
index b3beb1eba..9e0c772fd 100644
--- a/v2v/create_ovf.ml
+++ b/v2v/create_ovf.ml
@@ -40,6 +40,10 @@ let ovf_flavour_of_string = function
| "rhvexp" -> RHVExportStorageDomain
| flav -> invalid_arg flav
+let ovf_flavour_to_string = function
+ | OVirt -> "ovirt"
+ | RHVExportStorageDomain -> "rhvexp"
+
(* We set the creation time to be the same for all dates in
* all metadata files. All dates in OVF are UTC.
*)
diff --git a/v2v/create_ovf.mli b/v2v/create_ovf.mli
index 2d80660e3..8200b76f9 100644
--- a/v2v/create_ovf.mli
+++ b/v2v/create_ovf.mli
@@ -29,6 +29,9 @@ val ovf_flavours : string list
valid flavour. *)
val ovf_flavour_of_string : string -> ovf_flavour
+(** Convert an OVF flavour to its string representation. *)
+val ovf_flavour_to_string : ovf_flavour -> string
+
(** Create OVF and related files for RHV.
The format for RHV export storage domain is described in:
diff --git a/v2v/output_vdsm.ml b/v2v/output_vdsm.ml
index 92b3fd122..9a1b748bc 100644
--- a/v2v/output_vdsm.ml
+++ b/v2v/output_vdsm.ml
@@ -118,9 +118,10 @@ object
| "0.10" -> "" (* currently this is the default, so don't print it *)
| s -> sprintf " -oo vdsm-compat=%s" s)
(match vdsm_options.ovf_flavour with
- | Create_ovf.OVirt -> "-oo vdsm-ovf-flavour=ovf"
(* currently this is the default, so don't print it *)
- | Create_ovf.RHVExportStorageDomain -> "")
+ | Create_ovf.RHVExportStorageDomain -> ""
+ | flav -> sprintf "-oo vdsm-ovf-flavour=%s"
+ (Create_ovf.ovf_flavour_to_string flav))
method supported_firmware = [ TargetBIOS ]
--
2.21.0

View File

@ -0,0 +1,46 @@
From 2eeada3ec57760f57d5da473f32b359c6b55c616 Mon Sep 17 00:00:00 2001
From: Nir Soffer <nirsof@gmail.com>
Date: Mon, 2 Sep 2019 17:45:13 +0100
Subject: [PATCH] v2v: Set DISKTYPE=2 in RHV and VDSM meta files
(RHBZ#1746699).
Added in virt-p2v commit:
commit e83b6f50af34ce650063ecc520bfabab400e8e73
Author: Matthew Booth <mbooth@redhat.com>
Date: Fri Mar 26 09:40:20 2010 +0000
Add export to RHEV
Allow guests to be written to a RHEV NFS export storage domain.
Add 'rhev' output method and -osd command-line option.
Example command line:
virt-v2v -f virt-v2v.conf -ic 'esx://yellow.rhev.marston/' \
-o rhev -osd blue:/export/export RHEL3-32
This will connect to an ESX server and write the guest 'RHEL3-32' to
blue:/export/export, which is a pre-initialised RHEV export storage domain.
(cherry picked from commit fcfdbc9420b07e3003df38481afb9ccd22045e1a)
---
v2v/create_ovf.ml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/v2v/create_ovf.ml b/v2v/create_ovf.ml
index 91ff5198d..9aad5dd15 100644
--- a/v2v/create_ovf.ml
+++ b/v2v/create_ovf.ml
@@ -501,7 +501,7 @@ let create_meta_files output_alloc sd_uuid image_uuids overlays =
bpf "CTIME=%.0f\n" time;
bpf "MTIME=%.0f\n" time;
bpf "IMAGE=%s\n" image_uuid;
- bpf "DISKTYPE=1\n";
+ bpf "DISKTYPE=2\n";
bpf "PUUID=00000000-0000-0000-0000-000000000000\n";
bpf "LEGALITY=LEGAL\n";
bpf "POOL_UUID=\n";
--
2.26.2

View File

@ -1,42 +0,0 @@
From e61cbd740b84eb78a1ffc52223e4f1cc3202c978 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 5 Jun 2018 19:09:43 +0100
Subject: [PATCH] v2v: -o rhv-upload: Set inactivity timeout (RHBZ#1586198).
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This increases the inactivity timeout for transfers from the default
(60 seconds in oVirt < 4.2.3, 600 seconds in >= 4.2.3), up to 1 hour,
so that we should never hit it for ordinary transfers.
Note this requires oVirt >= 4.2.3. The corresponding oVirt fix was
https://bugzilla.redhat.com/1563278
I also replaced the deprecated image parameter with disk.
Thanks: Nir Soffer, Daniel Erez.
(cherry picked from commit f25404c65f8e078a3ca5bd5a1ab91343edd22506)
---
v2v/rhv-upload-plugin.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index 791c9e7d2..b4557b83c 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -123,9 +123,8 @@ def open(readonly):
# Create a new image transfer.
transfer = transfers_service.add(
types.ImageTransfer(
- image = types.Image(
- id = disk.id
- )
+ disk = types.Disk(id = disk.id),
+ inactivity_timeout = 3600,
)
)
debug("transfer.id = %r" % transfer.id)
--
2.21.0

View File

@ -1,136 +0,0 @@
From 24aef5baa9725e26efd37fa78b83f98629d77eba Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Wed, 21 Feb 2018 17:33:28 +0100
Subject: [PATCH] New API: inspect_get_osinfo
Try to guess the possible osinfo-db short ID for the specified OS.
Related to: https://bugzilla.redhat.com/show_bug.cgi?id=1544842
(cherry picked from commit 286b88891c2288fb7f64c9538296599ece04bcb1)
---
generator/actions_inspection.ml | 14 ++++++
lib/Makefile.am | 1 +
lib/inspect-osinfo.c | 75 +++++++++++++++++++++++++++++++++
3 files changed, 90 insertions(+)
create mode 100644 lib/inspect-osinfo.c
diff --git a/generator/actions_inspection.ml b/generator/actions_inspection.ml
index 0ac282435..ff5083114 100644
--- a/generator/actions_inspection.ml
+++ b/generator/actions_inspection.ml
@@ -770,4 +770,18 @@ advice before using trademarks in applications.
=back" };
+ { defaults with
+ name = "inspect_get_osinfo"; added = (1, 39, 1);
+ style = RString (RPlainString, "id"), [String (Mountable, "root")], [];
+ shortdesc = "get a possible osinfo short ID corresponding to this operating system";
+ longdesc = "\
+This function returns a possible short ID for libosinfo corresponding
+to the guest.
+
+I<Note:> The returned ID is only a guess by libguestfs, and nothing
+ensures that it actually exists in osinfo-db.
+
+If no ID could not be determined, then the string C<unknown> is
+returned." };
+
]
diff --git a/lib/Makefile.am b/lib/Makefile.am
index d075174d9..742b182cc 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -95,6 +95,7 @@ libguestfs_la_SOURCES = \
info.c \
inspect-apps.c \
inspect-icon.c \
+ inspect-osinfo.c \
journal.c \
launch.c \
launch-direct.c \
diff --git a/lib/inspect-osinfo.c b/lib/inspect-osinfo.c
new file mode 100644
index 000000000..816d317f1
--- /dev/null
+++ b/lib/inspect-osinfo.c
@@ -0,0 +1,75 @@
+/* libguestfs
+ * Copyright (C) 2018 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "guestfs.h"
+#include "guestfs-internal.h"
+#include "guestfs-internal-actions.h"
+
+char *
+guestfs_impl_inspect_get_osinfo (guestfs_h *g, const char *root)
+{
+ CLEANUP_FREE char *type = NULL;
+ CLEANUP_FREE char *distro = NULL;
+ int major, minor;
+
+ type = guestfs_inspect_get_type (g, root);
+ if (!type)
+ return NULL;
+ distro = guestfs_inspect_get_distro (g, root);
+ if (!distro)
+ return NULL;
+ major = guestfs_inspect_get_major_version (g, root);
+ minor = guestfs_inspect_get_minor_version (g, root);
+
+ if (STREQ (type, "linux")) {
+ if (STREQ (distro, "centos")) {
+ if (major >= 7)
+ return safe_asprintf (g, "%s%d.0", distro, major);
+ else if (major == 6)
+ return safe_asprintf (g, "%s%d.%d", distro, major, minor);
+ }
+ else if (STREQ (distro, "debian")) {
+ if (major >= 4)
+ return safe_asprintf (g, "%s%d", distro, major);
+ }
+ else if (STREQ (distro, "fedora") || STREQ (distro, "mageia"))
+ return safe_asprintf (g, "%s%d", distro, major);
+ else if (STREQ (distro, "sles")) {
+ if (minor == 0)
+ return safe_asprintf (g, "%s%d", distro, major);
+ else
+ return safe_asprintf (g, "%s%dsp%d", distro, major, minor);
+ }
+ else if (STREQ (distro, "ubuntu"))
+ return safe_asprintf (g, "%s%d.%02d", distro, major, minor);
+
+ if (major > 0 || minor > 0)
+ return safe_asprintf (g, "%s%d.%d", distro, major, minor);
+ }
+ else if (STREQ (type, "freebsd") || STREQ (type, "netbsd") || STREQ (type, "openbsd"))
+ return safe_asprintf (g, "%s%d.%d", distro, major, minor);
+ else if (STREQ (type, "dos")) {
+ if (STREQ (distro, "msdos"))
+ return safe_strdup (g, "msdos6.22");
+ }
+
+ /* No ID could be guessed, return "unknown". */
+ return safe_strdup (g, "unknown");
+}
--
2.21.0

View File

@ -0,0 +1,55 @@
From 41f3e803050b46fd79d8c2e728fc0425da05878c Mon Sep 17 00:00:00 2001
From: Daniel Erez <derez@redhat.com>
Date: Mon, 18 Mar 2019 18:51:26 +0200
Subject: [PATCH] v2v: rhv-upload-plugin - improve wait logic after finalize
(RHBZ#1680361)
After invoking transfer_service.finalize, check operation status by
examining DiskStatus. This is done instead of failing after a
predefined timeout regardless the status.
Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=1680361
Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
Tested-by: Ilanit Stein <istein@redhat.com>
(cherry picked from commit eeabb3fdc7756887b53106f455a7b54309130637)
---
v2v/rhv-upload-plugin.py | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index 2a950c5ed..4d61a089b 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -523,16 +523,23 @@ def close(h):
# waiting for the transfer object to cease to exist, which
# falls through to the exception case and then we can
# continue.
- endt = time.time() + timeout
+ disk_id = disk.id
+ start = time.time()
try:
while True:
time.sleep(1)
- tmp = transfer_service.get()
- if time.time() > endt:
- raise RuntimeError("timed out waiting for transfer "
- "to finalize")
+ disk_service = h['disk_service']
+ disk = disk_service.get()
+ if disk.status == types.DiskStatus.LOCKED:
+ if time.time() > start + timeout:
+ raise RuntimeError("timed out waiting for transfer "
+ "to finalize")
+ continue
+ if disk.status == types.DiskStatus.OK:
+ debug("finalized after %s seconds" % (time.time() - start))
+ break
except sdk.NotFoundError:
- pass
+ raise RuntimeError("transfer failed: disk %s not found" % disk_id)
# Write the disk ID file. Only do this on successful completion.
with builtins.open(params['diskid_file'], 'w') as fp:
--
2.26.2

View File

@ -1,99 +0,0 @@
From ee00f39eea1c97c5fcb9948b30586c9c106356d7 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Wed, 21 Feb 2018 17:37:30 +0100
Subject: [PATCH] inspector: show the per-OS osinfo guess (RHBZ#1544842)
Output also the osinfo guess for each OS in the generated XML output;
adapt the RNG schema, and the test data to it.
(cherry picked from commit 2f8ec91fc1f3e81c8fb81d45849bc7462ee13642)
---
inspector/expected-coreos.img.xml | 1 +
inspector/expected-debian.img.xml | 1 +
inspector/expected-fedora.img.xml | 1 +
inspector/expected-ubuntu.img.xml | 1 +
inspector/inspector.c | 7 +++++++
inspector/virt-inspector.rng | 1 +
6 files changed, 12 insertions(+)
diff --git a/inspector/expected-coreos.img.xml b/inspector/expected-coreos.img.xml
index e4a5d1134..0cdfba6e6 100644
--- a/inspector/expected-coreos.img.xml
+++ b/inspector/expected-coreos.img.xml
@@ -8,6 +8,7 @@
<major_version>899</major_version>
<minor_version>13</minor_version>
<hostname>coreos.invalid</hostname>
+ <osinfo>coreos899.13</osinfo>
<mountpoints>
<mountpoint dev="/dev/sda5">/</mountpoint>
<mountpoint dev="/dev/sda3">/usr</mountpoint>
diff --git a/inspector/expected-debian.img.xml b/inspector/expected-debian.img.xml
index 37ecfa049..6583dc262 100644
--- a/inspector/expected-debian.img.xml
+++ b/inspector/expected-debian.img.xml
@@ -11,6 +11,7 @@
<package_format>deb</package_format>
<package_management>apt</package_management>
<hostname>debian.invalid</hostname>
+ <osinfo>debian5</osinfo>
<mountpoints>
<mountpoint dev="/dev/debian/root">/</mountpoint>
<mountpoint dev="/dev/debian/usr">/usr</mountpoint>
diff --git a/inspector/expected-fedora.img.xml b/inspector/expected-fedora.img.xml
index 8d40e8cb7..df6060a73 100644
--- a/inspector/expected-fedora.img.xml
+++ b/inspector/expected-fedora.img.xml
@@ -11,6 +11,7 @@
<package_format>rpm</package_format>
<package_management>yum</package_management>
<hostname>fedora.invalid</hostname>
+ <osinfo>fedora14</osinfo>
<mountpoints>
<mountpoint dev="/dev/VG/Root">/</mountpoint>
<mountpoint dev="/dev/sda1">/boot</mountpoint>
diff --git a/inspector/expected-ubuntu.img.xml b/inspector/expected-ubuntu.img.xml
index c19c14cd5..4ebcd76d6 100644
--- a/inspector/expected-ubuntu.img.xml
+++ b/inspector/expected-ubuntu.img.xml
@@ -11,6 +11,7 @@
<package_format>deb</package_format>
<package_management>apt</package_management>
<hostname>ubuntu.invalid</hostname>
+ <osinfo>ubuntu10.10</osinfo>
<mountpoints>
<mountpoint dev="/dev/sda2">/</mountpoint>
<mountpoint dev="/dev/sda1">/boot</mountpoint>
diff --git a/inspector/inspector.c b/inspector/inspector.c
index d608b1b63..5075a8f04 100644
--- a/inspector/inspector.c
+++ b/inspector/inspector.c
@@ -443,6 +443,13 @@ output_root (xmlTextWriterPtr xo, char *root)
BAD_CAST str));
free (str);
+ str = guestfs_inspect_get_osinfo (g, root);
+ if (!str) exit (EXIT_FAILURE);
+ if (STRNEQ (str, "unknown"))
+ XMLERROR (-1,
+ xmlTextWriterWriteElement (xo, BAD_CAST "osinfo", BAD_CAST str));
+ free (str);
+
output_mountpoints (xo, root);
output_filesystems (xo, root);
diff --git a/inspector/virt-inspector.rng b/inspector/virt-inspector.rng
index 314785202..1e3a58af8 100644
--- a/inspector/virt-inspector.rng
+++ b/inspector/virt-inspector.rng
@@ -38,6 +38,7 @@
<optional><ref name="ospackageformat"/></optional>
<optional><ref name="ospackagemanagement"/></optional>
<optional><element name="hostname"><text/></element></optional>
+ <optional><element name="osinfo"><text/></element></optional>
<ref name="mountpoints"/>
<ref name="filesystems"/>
--
2.21.0

View File

@ -0,0 +1,61 @@
From b37ca67f769749b7b3b5d51e171b7cccfa3b5fd2 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Mon, 15 Apr 2019 17:24:42 +0200
Subject: [PATCH] v2v: -o rhv-upload: check whether the cluster exists
In the precheck script, check that the target cluster actually exists.
This will avoid errors when creating the VM after the data copying.
(cherry picked from commit 05e559549dab75f17e147f4a4eafbac868a7aa5d)
---
v2v/rhv-upload-precheck.py | 10 ++++++++++
v2v/test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py | 7 +++++++
2 files changed, 17 insertions(+)
diff --git a/v2v/rhv-upload-precheck.py b/v2v/rhv-upload-precheck.py
index 2798a29dd..b79f91b4a 100644
--- a/v2v/rhv-upload-precheck.py
+++ b/v2v/rhv-upload-precheck.py
@@ -70,4 +70,14 @@ if len(vms) > 0:
raise RuntimeError("VM already exists with name %s, id %s" %
(params['output_name'], vm.id))
+# Check whether the specified cluster exists.
+clusters_service = system_service.clusters_service()
+clusters = clusters_service.list(
+ search='name=%s' % params['rhv_cluster'],
+ case_sensitive=True,
+)
+if len(clusters) == 0:
+ raise RuntimeError("The cluster %s does not exist" %
+ (params['rhv_cluster']))
+
# Otherwise everything is OK, exit with no error.
diff --git a/v2v/test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py b/v2v/test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py
index 8d1058d67..cc4224ccd 100644
--- a/v2v/test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py
+++ b/v2v/test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py
@@ -39,6 +39,9 @@ class Connection(object):
return SystemService()
class SystemService(object):
+ def clusters_service(self):
+ return ClustersService()
+
def data_centers_service(self):
return DataCentersService()
@@ -54,6 +57,10 @@ class SystemService(object):
def vms_service(self):
return VmsService()
+class ClustersService(object):
+ def list(self, search=None, case_sensitive=False):
+ return ["Default"]
+
class DataCentersService(object):
def list(self, search=None, case_sensitive=False):
return []
--
2.26.2

View File

@ -1,90 +0,0 @@
From 5917bdc15f3b2e0c96ba5a9860cd36f968a28ec2 Mon Sep 17 00:00:00 2001
From: Nir Soffer <nirsof@gmail.com>
Date: Thu, 14 Jun 2018 21:16:01 +0300
Subject: [PATCH] v2v: -o rhv-upload: Optimize http request sending
When sending request with small or no payload, it is simpler and
possibly more efficient to use the high level HTTPSConnection.request(),
instead of the lower level APIs.
The only reason to use the lower level APIs is to avoid copying the
payload, or on python 2, to use a bigger buffer size when streaming a
file-like object.
(cherry picked from commit 77a412c0a1cd0e303a072fc5088c8f3bfed36583)
---
v2v/rhv-upload-plugin.py | 35 ++++++++++++++++-------------------
1 file changed, 16 insertions(+), 19 deletions(-)
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index b4557b83c..9ad354b84 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -237,12 +237,12 @@ def pread(h, count, offset):
transfer = h['transfer']
transfer_service = h['transfer_service']
- http.putrequest("GET", h['path'])
+ headers = {"Range", "bytes=%d-%d" % (offset, offset+count-1)}
# Authorization is only needed for old imageio.
if h['needs_auth']:
- http.putheader("Authorization", transfer.signed_ticket)
- http.putheader("Range", "bytes=%d-%d" % (offset, offset+count-1))
- http.endheaders()
+ headers["Authorization"] = transfer.signed_ticket
+
+ http.request("GET", h['path'], headers=headers)
r = http.getresponse()
# 206 = HTTP Partial Content.
@@ -297,11 +297,10 @@ def zero(h, count, offset, may_trim):
'size': count,
'flush': False}).encode()
- http.putrequest("PATCH", h['path'])
- http.putheader("Content-Type", "application/json")
- http.putheader("Content-Length", len(buf))
- http.endheaders()
- http.send(buf)
+ headers = {"Content-Type": "application/json",
+ "Content-Length": str(len(buf))}
+
+ http.request("PATCH", h['path'], body=buf, headers=headers)
r = http.getresponse()
if r.status != 200:
@@ -349,11 +348,10 @@ def trim(h, count, offset):
'size': count,
'flush': False}).encode()
- http.putrequest("PATCH", h['path'])
- http.putheader("Content-Type", "application/json")
- http.putheader("Content-Length", len(buf))
- http.endheaders()
- http.send(buf)
+ headers = {"Content-Type": "application/json",
+ "Content-Length": str(len(buf))}
+
+ http.request("PATCH", h['path'], body=buf, headers=headers)
r = http.getresponse()
if r.status != 200:
@@ -370,11 +368,10 @@ def flush(h):
# Construct the JSON request for flushing.
buf = json.dumps({'op': "flush"}).encode()
- http.putrequest("PATCH", h['path'])
- http.putheader("Content-Type", "application/json")
- http.putheader("Content-Length", len(buf))
- http.endheaders()
- http.send(buf)
+ headers = {"Content-Type": "application/json",
+ "Content-Length": str(len(buf))}
+
+ http.request("PATCH", h['path'], body=buf, headers=headers)
r = http.getresponse()
if r.status != 200:
--
2.21.0

View File

@ -0,0 +1,264 @@
From ae560843517da393492418bb61c3dee43e64af2c Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Thu, 12 Sep 2019 13:19:48 +0200
Subject: [PATCH] v2v: -o rhv-upload: split vmcheck out of precheck
Split the VM existance check out of the precheck script to a new vmcheck
script, and invoke that in #prepare_targets. Invoke the precheck script
in #precheck, as now it can be run with only values of command line
options.
This does not change which checks are performed; however, an invalid
cluster name will make virt-v2v fail way earlier (even before connecting
to the source).
(cherry picked from commit 6499fdc199790619745eee28fcae3421c32c4735)
---
v2v/Makefile.am | 8 ++-
v2v/output_rhv_upload.ml | 14 +++--
v2v/output_rhv_upload_precheck_source.mli | 2 +-
v2v/output_rhv_upload_vmcheck_source.mli | 19 ++++++
v2v/rhv-upload-precheck.py | 12 +---
v2v/rhv-upload-vmcheck.py | 73 +++++++++++++++++++++++
6 files changed, 111 insertions(+), 17 deletions(-)
create mode 100644 v2v/output_rhv_upload_vmcheck_source.mli
create mode 100644 v2v/rhv-upload-vmcheck.py
diff --git a/v2v/Makefile.am b/v2v/Makefile.am
index 53c137fc6..30f040d3e 100644
--- a/v2v/Makefile.am
+++ b/v2v/Makefile.am
@@ -26,7 +26,8 @@ BUILT_SOURCES = \
config.ml \
output_rhv_upload_createvm_source.ml \
output_rhv_upload_plugin_source.ml \
- output_rhv_upload_precheck_source.ml
+ output_rhv_upload_precheck_source.ml \
+ output_rhv_upload_vmcheck_source.ml
EXTRA_DIST = \
$(SOURCES_MLI) $(SOURCES_ML) $(SOURCES_C) \
@@ -36,6 +37,7 @@ EXTRA_DIST = \
rhv-upload-createvm.py \
rhv-upload-plugin.py \
rhv-upload-precheck.py \
+ rhv-upload-vmcheck.py \
v2v_unit_tests.ml \
virt-v2v.pod \
virt-v2v-copy-to-local.pod \
@@ -87,6 +89,7 @@ SOURCES_MLI = \
output_rhv_upload_createvm_source.mli \
output_rhv_upload_plugin_source.mli \
output_rhv_upload_precheck_source.mli \
+ output_rhv_upload_vmcheck_source.mli \
output_vdsm.mli \
parse_ova.mli \
parse_ovf_from_ova.mli \
@@ -152,6 +155,7 @@ SOURCES_ML = \
output_rhv_upload_createvm_source.ml \
output_rhv_upload_plugin_source.ml \
output_rhv_upload_precheck_source.ml \
+ output_rhv_upload_vmcheck_source.ml \
output_rhv_upload.ml \
output_vdsm.ml \
output_openstack.ml \
@@ -173,6 +177,8 @@ output_rhv_upload_plugin_source.ml: $(srcdir)/rhv-upload-plugin.py
$(srcdir)/embed.sh code $^ $@
output_rhv_upload_precheck_source.ml: $(srcdir)/rhv-upload-precheck.py
$(srcdir)/embed.sh code $^ $@
+output_rhv_upload_vmcheck_source.ml: $(srcdir)/rhv-upload-vmcheck.py
+ $(srcdir)/embed.sh code $^ $@
if HAVE_OCAML
diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml
index c2a5c72c7..adcbdf25f 100644
--- a/v2v/output_rhv_upload.ml
+++ b/v2v/output_rhv_upload.ml
@@ -94,10 +94,13 @@ class output_rhv_upload output_alloc output_conn
let diskid_file_of_id id = tmpdir // sprintf "diskid.%d" id in
- (* Create Python scripts for precheck, plugin and create VM. *)
+ (* Create Python scripts for precheck, vmcheck, plugin and create VM. *)
let precheck_script =
Python_script.create ~name:"rhv-upload-precheck.py"
Output_rhv_upload_precheck_source.code in
+ let vmcheck_script =
+ Python_script.create ~name:"rhv-upload-vmcheck.py"
+ Output_rhv_upload_vmcheck_source.code in
let plugin_script =
Python_script.create ~name:"rhv-upload-plugin.py"
Output_rhv_upload_plugin_source.code in
@@ -230,6 +233,9 @@ object
error_unless_nbdkit_working ();
error_unless_nbdkit_python_plugin_working ();
error_unless_output_alloc_sparse ();
+ (* Python code prechecks. *)
+ if Python_script.run_command precheck_script json_params [] <> 0 then
+ error (f_"failed server prechecks, see earlier errors");
if have_selinux then
error_unless_nbdkit_compiled_with_selinux ()
@@ -251,11 +257,11 @@ object
let json_params =
("output_name", JSON.String output_name) :: json_params in
- (* Python code prechecks. These can't run in #precheck because
+ (* Check that the VM does not exist. This can't run in #precheck because
* we need to know the name of the virtual machine.
*)
- if Python_script.run_command precheck_script json_params [] <> 0 then
- error (f_"failed server prechecks, see earlier errors");
+ if Python_script.run_command vmcheck_script json_params [] <> 0 then
+ error (f_"failed vmchecks, see earlier errors");
(* Create an nbdkit instance for each disk and set the
* target URI to point to the NBD socket.
diff --git a/v2v/output_rhv_upload_precheck_source.mli b/v2v/output_rhv_upload_precheck_source.mli
index c1bafa15b..aa33bc548 100644
--- a/v2v/output_rhv_upload_precheck_source.mli
+++ b/v2v/output_rhv_upload_precheck_source.mli
@@ -1,5 +1,5 @@
(* virt-v2v
- * Copyright (C) 2018 Red Hat Inc.
+ * Copyright (C) 2019 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/v2v/output_rhv_upload_vmcheck_source.mli b/v2v/output_rhv_upload_vmcheck_source.mli
new file mode 100644
index 000000000..c1bafa15b
--- /dev/null
+++ b/v2v/output_rhv_upload_vmcheck_source.mli
@@ -0,0 +1,19 @@
+(* virt-v2v
+ * 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.
+ *)
+
+val code : string
diff --git a/v2v/rhv-upload-precheck.py b/v2v/rhv-upload-precheck.py
index b79f91b4a..d6a58f0fc 100644
--- a/v2v/rhv-upload-precheck.py
+++ b/v2v/rhv-upload-precheck.py
@@ -1,6 +1,6 @@
# -*- python -*-
# oVirt or RHV pre-upload checks used by virt-v2v -o rhv-upload
-# Copyright (C) 2018 Red Hat Inc.
+# Copyright (C) 2018-2019 Red Hat Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -60,16 +60,6 @@ connection = sdk.Connection(
system_service = connection.system_service()
-# Find if a virtual machine already exists with that name.
-vms_service = system_service.vms_service()
-vms = vms_service.list(
- search = ("name=%s" % params['output_name']),
-)
-if len(vms) > 0:
- vm = vms[0]
- raise RuntimeError("VM already exists with name %s, id %s" %
- (params['output_name'], vm.id))
-
# Check whether the specified cluster exists.
clusters_service = system_service.clusters_service()
clusters = clusters_service.list(
diff --git a/v2v/rhv-upload-vmcheck.py b/v2v/rhv-upload-vmcheck.py
new file mode 100644
index 000000000..fbb884b94
--- /dev/null
+++ b/v2v/rhv-upload-vmcheck.py
@@ -0,0 +1,73 @@
+# -*- python -*-
+# oVirt or RHV VM existance check used by virt-v2v -o rhv-upload
+# Copyright (C) 2018-2019 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import json
+import logging
+import sys
+import time
+
+from http.client import HTTPSConnection
+from urllib.parse import urlparse
+
+import ovirtsdk4 as sdk
+import ovirtsdk4.types as types
+
+# Parameters are passed in via a JSON doc from the OCaml code.
+# Because this Python code ships embedded inside virt-v2v there
+# is no formal API here.
+params = None
+
+if len(sys.argv) != 2:
+ raise RuntimeError("incorrect number of parameters")
+
+# Parameters are passed in via a JSON document.
+with open(sys.argv[1], 'r') as fp:
+ params = json.load(fp)
+
+# What is passed in is a password file, read the actual password.
+with open(params['output_password'], 'r') as fp:
+ output_password = fp.read()
+output_password = output_password.rstrip()
+
+# Parse out the username from the output_conn URL.
+parsed = urlparse(params['output_conn'])
+username = parsed.username or "admin@internal"
+
+# Connect to the server.
+connection = sdk.Connection(
+ url = params['output_conn'],
+ username = username,
+ password = output_password,
+ ca_file = params['rhv_cafile'],
+ log = logging.getLogger(),
+ insecure = params['insecure'],
+)
+
+system_service = connection.system_service()
+
+# Find if a virtual machine already exists with that name.
+vms_service = system_service.vms_service()
+vms = vms_service.list(
+ search = ("name=%s" % params['output_name']),
+)
+if len(vms) > 0:
+ vm = vms[0]
+ raise RuntimeError("VM already exists with name %s, id %s" %
+ (params['output_name'], vm.id))
+
+# Otherwise everything is OK, exit with no error.
--
2.26.2

View File

@ -1,153 +0,0 @@
From c2ed35e2bc17bcacf333626b21cd6796d4d8d6cf Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 5 Jun 2018 13:27:43 +0100
Subject: [PATCH] v2v: -o rhv-upload: Log full imageio response on failure.
Thanks: Nir Soffer
(cherry picked from commit 831a75cd11c5a87e40fccdadcb62353f6a4d5a72)
---
v2v/rhv-upload-plugin.py | 69 ++++++++++++++++++++++++----------------
1 file changed, 42 insertions(+), 27 deletions(-)
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index 9ad354b84..7c5084efd 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -227,6 +227,32 @@ def can_flush(h):
def get_size(h):
return params['disk_size']
+# Any unexpected HTTP response status from the server will end up
+# calling this function which logs the full error, pauses the
+# transfer, sets the failed state, and raises a RuntimeError
+# exception.
+def request_failed(h, r, msg):
+ # Setting the failed flag in the handle causes the disk to be
+ # cleaned up on close.
+ h['failed'] = True
+ h['transfer_service'].pause()
+
+ status = r.status
+ reason = r.reason
+ try:
+ body = r.read()
+ except EnvironmentError as e:
+ body = "(Unable to read response body: %s)" % e
+
+ # Log the full error if we're verbose.
+ debug("unexpected response from imageio server:")
+ debug(msg)
+ debug("%d: %s" % (status, reason))
+ debug(body)
+
+ # Only a short error is included in the exception.
+ raise RuntimeError("%s: %d %s: %r", msg, status, reason, body[:200])
+
# For documentation see:
# https://github.com/oVirt/ovirt-imageio/blob/master/docs/random-io.md
# For examples of working code to read/write from the server, see:
@@ -247,16 +273,14 @@ def pread(h, count, offset):
r = http.getresponse()
# 206 = HTTP Partial Content.
if r.status != 206:
- h['transfer_service'].pause()
- h['failed'] = True
- raise RuntimeError("could not read sector (%d, %d): %d: %s" %
- (offset, count, r.status, r.reason))
+ request_failed(h, r,
+ "could not read sector offset %d size %d" %
+ (offset, count))
return r.read()
def pwrite(h, buf, offset):
http = h['http']
transfer = h['transfer']
- transfer_service = h['transfer_service']
count = len(buf)
h['highestwrite'] = max(h['highestwrite'], offset+count)
@@ -274,15 +298,13 @@ def pwrite(h, buf, offset):
r = http.getresponse()
if r.status != 200:
- transfer_service.pause()
- h['failed'] = True
- raise RuntimeError("could not write sector (%d, %d): %d: %s" %
- (offset, count, r.status, r.reason))
+ request_failed(h, r,
+ "could not write sector offset %d size %d" %
+ (offset, count))
def zero(h, count, offset, may_trim):
http = h['http']
transfer = h['transfer']
- transfer_service = h['transfer_service']
# Unlike the trim and flush calls, there is no 'can_zero' method
# so nbdkit could call this even if the server doesn't support
@@ -304,10 +326,9 @@ def zero(h, count, offset, may_trim):
r = http.getresponse()
if r.status != 200:
- transfer_service.pause()
- h['failed'] = True
- raise RuntimeError("could not zero sector (%d, %d): %d: %s" %
- (offset, count, r.status, r.reason))
+ request_failed(h, r,
+ "could not zero sector offset %d size %d" %
+ (offset, count))
def emulate_zero(h, count, offset):
# qemu-img convert starts by trying to zero/trim the whole device.
@@ -332,15 +353,13 @@ def emulate_zero(h, count, offset):
r = http.getresponse()
if r.status != 200:
- transfer_service.pause()
- h['failed'] = True
- raise RuntimeError("could not write zeroes (%d, %d): %d: %s" %
- (offset, count, r.status, r.reason))
+ request_failed(h, r,
+ "could not write zeroes offset %d size %d" %
+ (offset, count))
def trim(h, count, offset):
http = h['http']
transfer = h['transfer']
- transfer_service = h['transfer_service']
# Construct the JSON request for trimming.
buf = json.dumps({'op': "trim",
@@ -355,15 +374,13 @@ def trim(h, count, offset):
r = http.getresponse()
if r.status != 200:
- transfer_service.pause()
- h['failed'] = True
- raise RuntimeError("could not trim sector (%d, %d): %d: %s" %
- (offset, count, r.status, r.reason))
+ request_failed(h, r,
+ "could not trim sector offset %d size %d" %
+ (offset, count))
def flush(h):
http = h['http']
transfer = h['transfer']
- transfer_service = h['transfer_service']
# Construct the JSON request for flushing.
buf = json.dumps({'op': "flush"}).encode()
@@ -375,9 +392,7 @@ def flush(h):
r = http.getresponse()
if r.status != 200:
- transfer_service.pause()
- h['failed'] = True
- raise RuntimeError("could not flush: %d: %s" % (r.status, r.reason))
+ request_failed(h, r, "could not flush")
def delete_disk_on_failure(h):
disk_service = h['disk_service']
--
2.21.0

View File

@ -0,0 +1,53 @@
From f0f00c5f0ea1a726dd2c8501bcc269211f30e2a8 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Thu, 12 Sep 2019 14:17:36 +0200
Subject: [PATCH] v2v: -o rhv-upload: change precheck script to return a JSON
This way it is possible to communicate data from the precheck script
back to virt-v2v.
For now there are no results, so the resulting JSON is discarded.
(cherry picked from commit cc6e2a7f9ea53258c2edb758e3ec9beb7baa1fc6)
---
v2v/output_rhv_upload.ml | 8 +++++++-
v2v/rhv-upload-precheck.py | 6 +++++-
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml
index adcbdf25f..fd6f2e3e6 100644
--- a/v2v/output_rhv_upload.ml
+++ b/v2v/output_rhv_upload.ml
@@ -234,8 +234,14 @@ object
error_unless_nbdkit_python_plugin_working ();
error_unless_output_alloc_sparse ();
(* Python code prechecks. *)
- if Python_script.run_command precheck_script json_params [] <> 0 then
+ let precheck_fn = tmpdir // "v2vprecheck.json" in
+ let fd = Unix.openfile precheck_fn [O_WRONLY; O_CREAT] 0o600 in
+ if Python_script.run_command ~stdout_fd:fd
+ precheck_script json_params [] <> 0 then
error (f_"failed server prechecks, see earlier errors");
+ let json = JSON_parser.json_parser_tree_parse_file precheck_fn in
+ debug "precheck output parsed as: %s"
+ (JSON.string_of_doc ~fmt:JSON.Indented ["", json]);
if have_selinux then
error_unless_nbdkit_compiled_with_selinux ()
diff --git a/v2v/rhv-upload-precheck.py b/v2v/rhv-upload-precheck.py
index d6a58f0fc..de8a66c05 100644
--- a/v2v/rhv-upload-precheck.py
+++ b/v2v/rhv-upload-precheck.py
@@ -70,4 +70,8 @@ if len(clusters) == 0:
raise RuntimeError("The cluster %s does not exist" %
(params['rhv_cluster']))
-# Otherwise everything is OK, exit with no error.
+# Otherwise everything is OK, print a JSON with the results.
+results = {
+}
+
+json.dump(results, sys.stdout)
--
2.26.2

View File

@ -0,0 +1,169 @@
From ccd327919ca1fed3e10fdd3567ede0dc8cd5d0c3 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Thu, 12 Sep 2019 15:21:26 +0200
Subject: [PATCH] v2v: -o rhv-upload: improve lookup of specified resources
(RHBZ#1612653)
Improve the way the precheck script checks for the specified resources:
- look directly for a data center with the specified storage domain
- get the storage domain object from the storage domains attached to the
data center found
- similarly, look for the specified cluster among the ones attached to
the data center found
When everything is found, return the UUID of the storage domain, and of
the cluster back to virt-v2v, which will store them.
Similarly, rework the createvm script to directly get the requested
cluster, instead of looking for it once again. Also, since the UUID of
the storage domain is available in virt-v2v already, use it directly
instead of using a placeholder.
This should fix a number of issues:
- unexisting/unattached storage domains are rejected outright
- the cluster is rejected if not part of the same data center of the
selected storage domain
- renaming the specified storage domain during the data copying will not
cause the conversion to fail (which will still use the specified
storage domain, no matter the new name)
Based on the hints by Daniel Erez in RHBZ#1612653.
(cherry picked from commit c49aa4fe01aac82d4776dd2a3524ce16e6deed06)
---
v2v/output_rhv_upload.ml | 24 +++++++++++++++++++-----
v2v/rhv-upload-createvm.py | 11 ++++-------
v2v/rhv-upload-precheck.py | 30 ++++++++++++++++++++++++------
3 files changed, 47 insertions(+), 18 deletions(-)
diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml
index fd6f2e3e6..19bdfcf05 100644
--- a/v2v/output_rhv_upload.ml
+++ b/v2v/output_rhv_upload.ml
@@ -227,6 +227,11 @@ See also the virt-v2v-output-rhv(1) manual.")
object
inherit output
+ (* The storage domain UUID. *)
+ val mutable rhv_storagedomain_uuid = None
+ (* The cluster UUID. *)
+ val mutable rhv_cluster_uuid = None
+
method precheck () =
Python_script.error_unless_python_interpreter_found ();
error_unless_ovirtsdk4_module_available ();
@@ -242,6 +247,10 @@ object
let json = JSON_parser.json_parser_tree_parse_file precheck_fn in
debug "precheck output parsed as: %s"
(JSON.string_of_doc ~fmt:JSON.Indented ["", json]);
+ rhv_storagedomain_uuid <-
+ Some (JSON_parser.object_get_string "rhv_storagedomain_uuid" json);
+ rhv_cluster_uuid <-
+ Some (JSON_parser.object_get_string "rhv_cluster_uuid" json);
if have_selinux then
error_unless_nbdkit_compiled_with_selinux ()
@@ -388,11 +397,11 @@ If the messages above are not sufficient to diagnose the problem then add the
diskid
) targets in
- (* We don't have the storage domain UUID, but instead we write
- * in a magic value which the Python code (which can get it)
- * will substitute.
- *)
- let sd_uuid = "@SD_UUID@" in
+ (* The storage domain UUID. *)
+ let sd_uuid =
+ match rhv_storagedomain_uuid with
+ | None -> assert false
+ | Some uuid -> uuid in
(* The volume and VM UUIDs are made up. *)
let vol_uuids = List.map (fun _ -> uuidgen ()) targets
@@ -406,6 +415,11 @@ If the messages above are not sufficient to diagnose the problem then add the
OVirt in
let ovf = DOM.doc_to_string ovf in
+ let json_params =
+ match rhv_cluster_uuid with
+ | None -> assert false
+ | Some uuid -> ("rhv_cluster_uuid", JSON.String uuid) :: json_params in
+
let ovf_file = tmpdir // "vm.ovf" in
with_open_out ovf_file (fun chan -> output_string chan ovf);
if Python_script.run_command createvm_script json_params [ovf_file] <> 0
diff --git a/v2v/rhv-upload-createvm.py b/v2v/rhv-upload-createvm.py
index 1d0e8c95d..ed57a9b20 100644
--- a/v2v/rhv-upload-createvm.py
+++ b/v2v/rhv-upload-createvm.py
@@ -65,17 +65,14 @@ connection = sdk.Connection(
system_service = connection.system_service()
-# Get the storage domain UUID and substitute it into the OVF doc.
-sds_service = system_service.storage_domains_service()
-sd = sds_service.list(search=("name=%s" % params['output_storage']))[0]
-sd_uuid = sd.id
-
-ovf = ovf.replace("@SD_UUID@", sd_uuid)
+# Get the cluster.
+cluster = system_service.clusters_service().cluster_service(params['rhv_cluster_uuid'])
+cluster = cluster.get()
vms_service = system_service.vms_service()
vm = vms_service.add(
types.Vm(
- cluster=types.Cluster(name = params['rhv_cluster']),
+ cluster=cluster,
initialization=types.Initialization(
configuration = types.Configuration(
type = types.ConfigurationType.OVA,
diff --git a/v2v/rhv-upload-precheck.py b/v2v/rhv-upload-precheck.py
index de8a66c05..725a8dc9e 100644
--- a/v2v/rhv-upload-precheck.py
+++ b/v2v/rhv-upload-precheck.py
@@ -60,18 +60,36 @@ connection = sdk.Connection(
system_service = connection.system_service()
-# Check whether the specified cluster exists.
-clusters_service = system_service.clusters_service()
-clusters = clusters_service.list(
- search='name=%s' % params['rhv_cluster'],
+# Check whether there is a datacenter for the specified storage.
+data_centers = system_service.data_centers_service().list(
+ search='storage.name=%s' % params['output_storage'],
case_sensitive=True,
)
+if len(data_centers) == 0:
+ # The storage domain is not attached to a datacenter
+ # (shouldn't happen, would fail on disk creation).
+ raise RuntimeError("The storage domain %s is not attached to a DC" %
+ (params['output_storage']))
+datacenter = data_centers[0]
+
+# Get the storage domain.
+storage_domains = connection.follow_link(datacenter.storage_domains)
+storage_domain = [sd for sd in storage_domains if sd.name == params['output_storage']][0]
+
+# Get the cluster.
+clusters = connection.follow_link(datacenter.clusters)
+clusters = [cluster for cluster in clusters if cluster.name == params['rhv_cluster']]
if len(clusters) == 0:
- raise RuntimeError("The cluster %s does not exist" %
- (params['rhv_cluster']))
+ raise RuntimeError("The cluster %s is not part of the DC %s, "
+ "where the storage domain %s is" %
+ (params['rhv_cluster'], datacenter.name,
+ params['output_storage']))
+cluster = clusters[0]
# Otherwise everything is OK, print a JSON with the results.
results = {
+ "rhv_storagedomain_uuid": storage_domain.id,
+ "rhv_cluster_uuid": cluster.id,
}
json.dump(results, sys.stdout)
--
2.26.2

View File

@ -1,112 +0,0 @@
From 6cd873ff9a6ba6fed0534a253148b4daf48f0190 Mon Sep 17 00:00:00 2001
From: Nir Soffer <nirsof@gmail.com>
Date: Mon, 25 Jun 2018 19:22:13 +0300
Subject: [PATCH] v2v: rvh-upload-plugin: Always read the response
Python manual warns[1]:
Note that you must have read the whole response before you can send
a new request to the server.
The reason for this warning is exposed only when the server is using
keep alive connections. When the response is not read, sending a new
request will fail with:
httplib.ResponseNotReady
Even if Content-Length was 0 or the request has no content. The failure
looks like this when using --verbose:
nbdkit: python[1]: debug: zero count=33554432 offset=0 may_trim=1 fua=0
nbdkit: python[1]: debug: zero count=33554432 offset=33554432 may_trim=1 fua=0
nbdkit: python[1]: error: /home/nsoffer/src/libguestfs/tmp/rhvupload.Au2B5I/rhv-upload-plugin.py: zero: error: Request-sent
nbdkit: python[1]: debug: sending error reply: Input/output error
qemu-img: error writing zeroes at offset 0: Input/output error
Change all requests to read the whole response.
Tested with imageio patch supporting keep alive connections:
https://gerrit.ovirt.org/#/c/92296/
[1] https://docs.python.org/3.8/library/http.client.html#http.client.HTTPConnection.getresponse
(cherry picked from commit f4e0a8342dbeb2c779c76e1807a37b24a0c96feb)
---
v2v/rhv-upload-plugin.py | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index 7c5084efd..2eec375f7 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -197,11 +197,13 @@ def get_options(h):
http.endheaders()
r = http.getresponse()
+ data = r.read()
+
if r.status == 200:
# New imageio never needs authentication.
h['needs_auth'] = False
- j = json.loads(r.read())
+ j = json.loads(data)
h['can_zero'] = "zero" in j['features']
h['can_trim'] = "trim" in j['features']
h['can_flush'] = "flush" in j['features']
@@ -276,6 +278,7 @@ def pread(h, count, offset):
request_failed(h, r,
"could not read sector offset %d size %d" %
(offset, count))
+
return r.read()
def pwrite(h, buf, offset):
@@ -302,6 +305,8 @@ def pwrite(h, buf, offset):
"could not write sector offset %d size %d" %
(offset, count))
+ r.read()
+
def zero(h, count, offset, may_trim):
http = h['http']
transfer = h['transfer']
@@ -330,6 +335,8 @@ def zero(h, count, offset, may_trim):
"could not zero sector offset %d size %d" %
(offset, count))
+ r.read()
+
def emulate_zero(h, count, offset):
# qemu-img convert starts by trying to zero/trim the whole device.
# Since we've just created a new disk it's safe to ignore these
@@ -357,6 +364,8 @@ def emulate_zero(h, count, offset):
"could not write zeroes offset %d size %d" %
(offset, count))
+ r.read()
+
def trim(h, count, offset):
http = h['http']
transfer = h['transfer']
@@ -378,6 +387,8 @@ def trim(h, count, offset):
"could not trim sector offset %d size %d" %
(offset, count))
+ r.read()
+
def flush(h):
http = h['http']
transfer = h['transfer']
@@ -394,6 +405,8 @@ def flush(h):
if r.status != 200:
request_failed(h, r, "could not flush")
+ r.read()
+
def delete_disk_on_failure(h):
disk_service = h['disk_service']
disk_service.remove()
--
2.21.0

View File

@ -0,0 +1,36 @@
From 5883b1efc1c54742bed7f56f4b1522061321c8f9 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Fri, 13 Sep 2019 12:40:34 +0200
Subject: [PATCH] v2v: -o rhv-upload: tell whether a SD actually exists
If there is no DC with the specified storage domain attached to it, it
can mean that the SD does not exist.
(cherry picked from commit 2b39c27b7f1e72f3a3bf3a616e4576af691beb88)
---
v2v/rhv-upload-precheck.py | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/v2v/rhv-upload-precheck.py b/v2v/rhv-upload-precheck.py
index 725a8dc9e..1b344ba27 100644
--- a/v2v/rhv-upload-precheck.py
+++ b/v2v/rhv-upload-precheck.py
@@ -66,6 +66,15 @@ data_centers = system_service.data_centers_service().list(
case_sensitive=True,
)
if len(data_centers) == 0:
+ storage_domains = system_service.storage_domains_service().list(
+ search='name=%s' % params['output_storage'],
+ case_sensitive=True,
+ )
+ if len(storage_domains) == 0:
+ # The storage domain does not even exist.
+ raise RuntimeError("The storage domain %s does not exist" %
+ (params['output_storage']))
+
# The storage domain is not attached to a datacenter
# (shouldn't happen, would fail on disk creation).
raise RuntimeError("The storage domain %s is not attached to a DC" %
--
2.26.2

View File

@ -1,35 +0,0 @@
From 47fd85a883892e2070a2287cc9411896645ab3bf Mon Sep 17 00:00:00 2001
From: Nir Soffer <nirsof@gmail.com>
Date: Mon, 25 Jun 2018 20:56:52 +0300
Subject: [PATCH] v2v: rhv-upload-plugin: Fix name error
"http" and "transfer" variables were missing in emulate_zero, so the
code would fail with NameError. This can happen only when communicating
with old imageio versions not supporting the "zero" feature.
Testing with qemu-img 2.12 show that we never send emulated zero request
because of the highestwrite mechanism, but it can break with older
qemu-img-rhev used on RHEL.
(cherry picked from commit 0ae61ce99c351f9cda598016fb55ccc50313df67)
---
v2v/rhv-upload-plugin.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index 2eec375f7..10887c031 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -338,6 +338,9 @@ def zero(h, count, offset, may_trim):
r.read()
def emulate_zero(h, count, offset):
+ http = h['http']
+ transfer = h['transfer']
+
# qemu-img convert starts by trying to zero/trim the whole device.
# Since we've just created a new disk it's safe to ignore these
# requests as long as they are smaller than the highest write seen.
--
2.21.0

View File

@ -0,0 +1,76 @@
From 7baca2397e3e494fa727e63e9a2d34b81b78c298 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Mon, 16 Sep 2019 14:01:14 +0200
Subject: [PATCH] v2v: add output#disk_copied hook
Add a simple method in the Output class to do work right after a disk
was successfully copied.
(cherry picked from commit 74ee936505acf56d01f9b819588e7902a9401e81)
---
v2v/types.ml | 1 +
v2v/types.mli | 8 ++++++++
v2v/v2v.ml | 9 ++++++++-
3 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/v2v/types.ml b/v2v/types.ml
index 77f879200..714b30014 100644
--- a/v2v/types.ml
+++ b/v2v/types.ml
@@ -521,6 +521,7 @@ class virtual output = object
method override_output_format (_ : overlay) = (None : string option)
method virtual prepare_targets : source -> (string * overlay) list -> target_buses -> guestcaps -> inspect -> target_firmware -> target_file list
method disk_create = (open_guestfs ())#disk_create
+ method disk_copied (_ : target) (_ : int) (_ : int) = ()
method virtual create_metadata : source -> target list -> target_buses -> guestcaps -> inspect -> target_firmware -> unit
method keep_serial_console = true
method install_rhev_apt = false
diff --git a/v2v/types.mli b/v2v/types.mli
index be9406100..f595ab0ef 100644
--- a/v2v/types.mli
+++ b/v2v/types.mli
@@ -441,6 +441,10 @@ end
│ by running qemu-img convert.
+ output#disk_copied The output mode is notified about the
+ │ successful copy of each disk.
+ │
+ ▼
output#create_metadata VM should be created from the metadata
supplied. Also any finalization can
be done here.
@@ -485,6 +489,10 @@ class virtual output : object
(** Called in order to create disks on the target. The method has the
same signature as Guestfs#disk_create. Normally you should {b not}
define this since the default method calls Guestfs#disk_create. *)
+ method disk_copied : target -> int -> int -> unit
+ (** Called after a disk was successfully copied on the target.
+ The second parameter is the index of the copied disk (starting
+ from 0), and the third is the number of disks in total. *)
method virtual create_metadata : source -> target list -> target_buses -> guestcaps -> inspect -> target_firmware -> unit
(** Called after conversion and copying to create metadata and
do any finalization. *)
diff --git a/v2v/v2v.ml b/v2v/v2v.ml
index 277d8f2c7..63e809030 100644
--- a/v2v/v2v.ml
+++ b/v2v/v2v.ml
@@ -798,7 +798,14 @@ and copy_targets cmdline targets input output =
pc;
if pc < 0. then eprintf " ! ESTIMATE TOO LOW !";
eprintf "\n%!";
- )
+ );
+
+ (* Let the output mode know that the disk was copied successfully,
+ * so it can perform any operations without waiting for all the
+ * other disks to be copied (i.e. before the metadata is actually
+ * created).
+ *)
+ output#disk_copied t i nr_disks
) targets
(* Update the target_actual_size field in the target structure. *)
--
2.26.2

View File

@ -1,52 +0,0 @@
From 6e683fa651864a04a1c4e2a326d84cfc9330d706 Mon Sep 17 00:00:00 2001
From: Nir Soffer <nirsof@gmail.com>
Date: Tue, 26 Jun 2018 01:43:01 +0300
Subject: [PATCH] v2v: rhv-upload-plugin: Remove unused variables
Remove some instances of "transfer" and "transfer_service" that are not
used in current code.
(cherry picked from commit 32ab53cecd78ee5c140f17e5792710698627d265)
---
v2v/rhv-upload-plugin.py | 4 ----
1 file changed, 4 deletions(-)
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index 10887c031..5c036c46a 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -263,7 +263,6 @@ def request_failed(h, r, msg):
def pread(h, count, offset):
http = h['http']
transfer = h['transfer']
- transfer_service = h['transfer_service']
headers = {"Range", "bytes=%d-%d" % (offset, offset+count-1)}
# Authorization is only needed for old imageio.
@@ -309,7 +308,6 @@ def pwrite(h, buf, offset):
def zero(h, count, offset, may_trim):
http = h['http']
- transfer = h['transfer']
# Unlike the trim and flush calls, there is no 'can_zero' method
# so nbdkit could call this even if the server doesn't support
@@ -371,7 +369,6 @@ def emulate_zero(h, count, offset):
def trim(h, count, offset):
http = h['http']
- transfer = h['transfer']
# Construct the JSON request for trimming.
buf = json.dumps({'op': "trim",
@@ -394,7 +391,6 @@ def trim(h, count, offset):
def flush(h):
http = h['http']
- transfer = h['transfer']
# Construct the JSON request for flushing.
buf = json.dumps({'op': "flush"}).encode()
--
2.21.0

View File

@ -1,122 +0,0 @@
From 1d2058c08b9eff607127d199b574273100e9ba55 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 19 Jun 2018 18:02:21 +0100
Subject: [PATCH] v2v: -o rhv-upload: Always fetch server options when opening
the connection.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Previously we lazily requested the server options in the can_*
callbacks. The can_* callbacks are always called by nbdkit straight
after open, so this just adds complexity for no benefit. This change
simply makes the code always fetch the server options during the open
callback.
This is — functionally at least — mostly just refactoring. However I
also added a useful debug message so we can see what features the
imageio server is offering.
(cherry picked from commit a1e1f6ec887c2a7973612d2edf7066fd3194ba0b)
---
v2v/rhv-upload-plugin.py | 63 +++++++++++++++++++---------------------
1 file changed, 30 insertions(+), 33 deletions(-)
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index 5c036c46a..f215eaecf 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -165,34 +165,13 @@ def open(readonly):
context = context
)
- # Save everything we need to make requests in the handle.
- return {
- 'can_flush': False,
- 'can_trim': False,
- 'can_zero': False,
- 'connection': connection,
- 'disk': disk,
- 'disk_service': disk_service,
- 'failed': False,
- 'got_options': False,
- 'highestwrite': 0,
- 'http': http,
- 'needs_auth': not params['rhv_direct'],
- 'path': destination_url.path,
- 'transfer': transfer,
- 'transfer_service': transfer_service,
- }
+ # The first request is to fetch the features of the server.
+ needs_auth = not params['rhv_direct']
+ can_flush = False
+ can_trim = False
+ can_zero = False
-# Can we issue zero, trim or flush requests?
-def get_options(h):
- if h['got_options']:
- return
- h['got_options'] = True
-
- http = h['http']
- transfer = h['transfer']
-
- http.putrequest("OPTIONS", h['path'])
+ http.putrequest("OPTIONS", destination_url.path)
http.putheader("Authorization", transfer.signed_ticket)
http.endheaders()
@@ -201,12 +180,12 @@ def get_options(h):
if r.status == 200:
# New imageio never needs authentication.
- h['needs_auth'] = False
+ needs_auth = False
j = json.loads(data)
- h['can_zero'] = "zero" in j['features']
- h['can_trim'] = "trim" in j['features']
- h['can_flush'] = "flush" in j['features']
+ can_flush = "flush" in j['features']
+ can_trim = "trim" in j['features']
+ can_zero = "zero" in j['features']
# Old imageio servers returned either 405 Method Not Allowed or
# 204 No Content (with an empty body). If we see that we leave
@@ -218,12 +197,30 @@ def get_options(h):
raise RuntimeError("could not use OPTIONS request: %d: %s" %
(r.status, r.reason))
+ debug("imageio features: flush=%r trim=%r zero=%r" %
+ (can_flush, can_trim, can_zero))
+
+ # Save everything we need to make requests in the handle.
+ return {
+ 'can_flush': can_flush,
+ 'can_trim': can_trim,
+ 'can_zero': can_zero,
+ 'connection': connection,
+ 'disk': disk,
+ 'disk_service': disk_service,
+ 'failed': False,
+ 'highestwrite': 0,
+ 'http': http,
+ 'needs_auth': needs_auth,
+ 'path': destination_url.path,
+ 'transfer': transfer,
+ 'transfer_service': transfer_service,
+ }
+
def can_trim(h):
- get_options(h)
return h['can_trim']
def can_flush(h):
- get_options(h)
return h['can_flush']
def get_size(h):
--
2.21.0

View File

@ -0,0 +1,84 @@
From 9ae4cc6feaf66cf34b9cdf0cf2c251ed7ef61259 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Mon, 16 Sep 2019 14:07:22 +0200
Subject: [PATCH] v2v: -o rhv-upload: collect disks UUIDs right after copy
Instead of waiting for the completion of the nbdkit transfers to get the
UUIDs of the disks, use the new #disk_copied hook to do that after each
disk is copied.
This has almost no behaviour on rhv-upload, except for the --no-copy
mode:
- previously it used to hit the 5 minute timeout while waiting for the
finalization of the first disk
- now it asserts on the different number of collected UUIDs vs the
actual targets; at the moment there is nothing else that can be done,
as this assumption is needed e.g. when creating the OVF file
(cherry picked from commit 7b93ad6a32f09043bf870202b59bea83d47e0c3a)
---
v2v/output_rhv_upload.ml | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml
index 19bdfcf05..382ad0d93 100644
--- a/v2v/output_rhv_upload.ml
+++ b/v2v/output_rhv_upload.ml
@@ -231,6 +231,8 @@ object
val mutable rhv_storagedomain_uuid = None
(* The cluster UUID. *)
val mutable rhv_cluster_uuid = None
+ (* List of disk UUIDs. *)
+ val mutable disks_uuids = []
method precheck () =
Python_script.error_unless_python_interpreter_found ();
@@ -379,23 +381,21 @@ If the messages above are not sufficient to diagnose the problem then add the
TargetURI ("json:" ^ JSON.string_of_doc json_params)
) overlays
- method create_metadata source targets _ guestcaps inspect target_firmware =
- (* Get the UUIDs of each disk image. These files are written
- * out by the nbdkit plugins on successful finalization of the
+ method disk_copied t i nr_disks =
+ (* Get the UUID of the disk image. This file is written
+ * out by the nbdkit plugin on successful finalization of the
* transfer.
*)
- let nr_disks = List.length targets in
- let image_uuids =
- List.mapi (
- fun i t ->
- let id = t.target_overlay.ov_source.s_disk_id in
- let diskid_file = diskid_file_of_id id in
- if not (wait_for_file diskid_file finalization_timeout) then
- error (f_"transfer of disk %d/%d failed, see earlier error messages")
- (i+1) nr_disks;
- let diskid = read_whole_file diskid_file in
- diskid
- ) targets in
+ let id = t.target_overlay.ov_source.s_disk_id in
+ let diskid_file = diskid_file_of_id id in
+ if not (wait_for_file diskid_file finalization_timeout) then
+ error (f_"transfer of disk %d/%d failed, see earlier error messages")
+ (i+1) nr_disks;
+ let diskid = read_whole_file diskid_file in
+ disks_uuids <- disks_uuids @ [diskid];
+
+ method create_metadata source targets _ guestcaps inspect target_firmware =
+ assert (List.length disks_uuids = List.length targets);
(* The storage domain UUID. *)
let sd_uuid =
@@ -411,7 +411,7 @@ If the messages above are not sufficient to diagnose the problem then add the
let ovf =
Create_ovf.create_ovf source targets guestcaps inspect
target_firmware output_alloc
- sd_uuid image_uuids vol_uuids vm_uuid
+ sd_uuid disks_uuids vol_uuids vm_uuid
OVirt in
let ovf = DOM.doc_to_string ovf in
--
2.26.2

View File

@ -1,141 +0,0 @@
From db7e06935bfd20e02110549371a5174e68a45cf0 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Mon, 18 Jun 2018 15:34:37 +0100
Subject: [PATCH] v2v: -o rhv-upload: Use Unix domain socket to access imageio
(RHBZ#1588088).
In the case where virt-v2v runs on the same server as the imageio
daemon that we are talking to, it may be possible to optimize access
using a Unix domain socket.
This is only an optimization. If it fails or if we're not running on
the same server it will fall back to the usual HTTPS over TCP
connection.
Thanks: Nir Soffer, Daniel Erez.
(cherry picked from commit b7a2e6270d53200d2df471c36a1fb2b46db8bbac)
---
v2v/rhv-upload-plugin.py | 61 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 58 insertions(+), 3 deletions(-)
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index f215eaecf..8805e3552 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -19,11 +19,12 @@
import builtins
import json
import logging
+import socket
import ssl
import sys
import time
-from http.client import HTTPSConnection
+from http.client import HTTPSConnection, HTTPConnection
from urllib.parse import urlparse
import ovirtsdk4 as sdk
@@ -56,6 +57,28 @@ def debug(s):
print(s, file=sys.stderr)
sys.stderr.flush()
+def find_host(connection):
+ """Return the current host object or None."""
+ try:
+ with builtins.open("/etc/vdsm/vdsm.id") as f:
+ vdsm_id = f.readline().strip()
+ except Exception as e:
+ return None
+ debug("hw_id = %r" % vdsm_id)
+
+ hosts_service = connection.system_service().hosts_service()
+ hosts = hosts_service.list(
+ search="hw_id=%s" % vdsm_id,
+ case_sensitive=False,
+ )
+ if len(hosts) == 0:
+ return None
+
+ host = hosts[0]
+ debug("host.id = %r" % host.id)
+
+ return types.Host(id = host.id)
+
def open(readonly):
# Parse out the username from the output_conn URL.
parsed = urlparse(params['output_conn'])
@@ -121,9 +144,11 @@ def open(readonly):
transfers_service = system_service.image_transfers_service()
# Create a new image transfer.
+ host = find_host(connection)
transfer = transfers_service.add(
types.ImageTransfer(
disk = types.Disk(id = disk.id),
+ host = host,
inactivity_timeout = 3600,
)
)
@@ -170,6 +195,7 @@ def open(readonly):
can_flush = False
can_trim = False
can_zero = False
+ unix_socket = None
http.putrequest("OPTIONS", destination_url.path)
http.putheader("Authorization", transfer.signed_ticket)
@@ -186,6 +212,7 @@ def open(readonly):
can_flush = "flush" in j['features']
can_trim = "trim" in j['features']
can_zero = "zero" in j['features']
+ unix_socket = j.get('unix_socket')
# Old imageio servers returned either 405 Method Not Allowed or
# 204 No Content (with an empty body). If we see that we leave
@@ -197,8 +224,17 @@ def open(readonly):
raise RuntimeError("could not use OPTIONS request: %d: %s" %
(r.status, r.reason))
- debug("imageio features: flush=%r trim=%r zero=%r" %
- (can_flush, can_trim, can_zero))
+ debug("imageio features: flush=%r trim=%r zero=%r unix_socket=%r" %
+ (can_flush, can_trim, can_zero, unix_socket))
+
+ # If we are connected to imageio on the local host and the
+ # transfer features a unix_socket then we can reconnect to that.
+ if host is not None and unix_socket is not None:
+ try:
+ http = UnixHTTPConnection(unix_socket)
+ debug("optimizing connection using unix socket %r" % unix_socket)
+ except:
+ pass
# Save everything we need to make requests in the handle.
return {
@@ -463,3 +499,22 @@ def close(h):
raise
connection.close()
+
+# Modify http.client.HTTPConnection to work over a Unix domain socket.
+# Derived from uhttplib written by Erik van Zijst under an MIT license.
+# (https://pypi.org/project/uhttplib/)
+# Ported to Python 3 by Irit Goihman.
+
+class UnsupportedError(Exception):
+ pass
+
+class UnixHTTPConnection(HTTPConnection):
+ def __init__(self, path, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
+ self.path = path
+ HTTPConnection.__init__(self, "localhost", timeout=timeout)
+
+ def connect(self):
+ self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ if self.timeout is not socket._GLOBAL_DEFAULT_TIMEOUT:
+ self.sock.settimeout(timeout)
+ self.sock.connect(self.path)
--
2.21.0

View File

@ -0,0 +1,201 @@
From 9d7503382f33a7721378ec586ea718c63a0ec3b6 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Thu, 19 Sep 2019 12:19:09 +0200
Subject: [PATCH] v2v: -o rhv-upload: add -oo rhv-disk-uuid option
This way it is possible to override the UUIDs of the uploaded disks,
instead of letting RHV generate them.
This can be useful to force certain UUIDs, and to specify the disks in
--no-copy mode (which now can be used).
(cherry picked from commit 537ba8357e44ca3aa8878a2ac98e9476a570d3f4)
---
v2v/output_rhv_upload.ml | 43 ++++++++++++++++++++++++++++++++-----
v2v/rhv-upload-plugin.py | 2 ++
v2v/virt-v2v-output-rhv.pod | 24 +++++++++++++++++++++
3 files changed, 64 insertions(+), 5 deletions(-)
diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml
index 382ad0d93..206657a2b 100644
--- a/v2v/output_rhv_upload.ml
+++ b/v2v/output_rhv_upload.ml
@@ -32,6 +32,7 @@ type rhv_options = {
rhv_cluster : string option;
rhv_direct : bool;
rhv_verifypeer : bool;
+ rhv_disk_uuids : string list option;
}
let print_output_options () =
@@ -41,6 +42,11 @@ let print_output_options () =
-oo rhv-cluster=CLUSTERNAME Set RHV cluster name.
-oo rhv-direct[=true|false] Use direct transfer mode (default: false).
-oo rhv-verifypeer[=true|false] Verify server identity (default: false).
+
+You can override the UUIDs of the disks, instead of using autogenerated UUIDs
+after their uploads (if you do, you must supply one for each disk):
+
+ -oo rhv-disk-uuid=UUID Disk UUID
")
let parse_output_options options =
@@ -48,6 +54,7 @@ let parse_output_options options =
let rhv_cluster = ref None in
let rhv_direct = ref false in
let rhv_verifypeer = ref false in
+ let rhv_disk_uuids = ref None in
List.iter (
function
@@ -63,6 +70,8 @@ let parse_output_options options =
| "rhv-direct", v -> rhv_direct := bool_of_string v
| "rhv-verifypeer", "" -> rhv_verifypeer := true
| "rhv-verifypeer", v -> rhv_verifypeer := bool_of_string v
+ | "rhv-disk-uuid", v ->
+ rhv_disk_uuids := Some (v :: (Option.default [] !rhv_disk_uuids))
| k, _ ->
error (f_"-o rhv-upload: unknown output option -oo %s") k
) options;
@@ -75,8 +84,9 @@ let parse_output_options options =
let rhv_cluster = !rhv_cluster in
let rhv_direct = !rhv_direct in
let rhv_verifypeer = !rhv_verifypeer in
+ let rhv_disk_uuids = Option.map List.rev !rhv_disk_uuids in
- { rhv_cafile; rhv_cluster; rhv_direct; rhv_verifypeer }
+ { rhv_cafile; rhv_cluster; rhv_direct; rhv_verifypeer; rhv_disk_uuids }
let nbdkit_python_plugin = Config.virt_v2v_nbdkit_python_plugin
let pidfile_timeout = 30
@@ -270,6 +280,16 @@ object
method install_rhev_apt = true
method prepare_targets source overlays _ _ _ _ =
+ let uuids =
+ match rhv_options.rhv_disk_uuids with
+ | None ->
+ List.map (fun _ -> None) overlays
+ | Some uuids ->
+ if List.length uuids <> List.length overlays then
+ error (f_"the number of -oo rhv-disk-uuid parameters passed on the command line has to match the number of guest disk images (for this guest: %d)")
+ (List.length overlays);
+ List.map (fun uuid -> Some uuid) uuids in
+
let output_name = source.s_name in
let json_params =
("output_name", JSON.String output_name) :: json_params in
@@ -284,7 +304,7 @@ object
* target URI to point to the NBD socket.
*)
List.map (
- fun (target_format, ov) ->
+ fun ((target_format, ov), uuid) ->
let id = ov.ov_source.s_disk_id in
let disk_name = sprintf "%s-%03d" output_name id in
let json_params =
@@ -310,6 +330,12 @@ object
let json_params =
("diskid_file", JSON.String diskid_file) :: json_params in
+ let json_params =
+ match uuid with
+ | None -> json_params
+ | Some uuid ->
+ ("rhv_disk_uuid", JSON.String uuid) :: json_params in
+
(* Write the JSON parameters to a file. *)
let json_param_file = tmpdir // sprintf "params%d.json" id in
with_open_out
@@ -379,7 +405,7 @@ If the messages above are not sufficient to diagnose the problem then add the
"file.export", JSON.String "/";
] in
TargetURI ("json:" ^ JSON.string_of_doc json_params)
- ) overlays
+ ) (List.combine overlays uuids)
method disk_copied t i nr_disks =
(* Get the UUID of the disk image. This file is written
@@ -395,7 +421,14 @@ If the messages above are not sufficient to diagnose the problem then add the
disks_uuids <- disks_uuids @ [diskid];
method create_metadata source targets _ guestcaps inspect target_firmware =
- assert (List.length disks_uuids = List.length targets);
+ let image_uuids =
+ match rhv_options.rhv_disk_uuids, disks_uuids with
+ | None, [] ->
+ error (f_"there must be -oo rhv-disk-uuid parameters passed on the command line to specify the UUIDs of guest disk images (for this guest: %d)")
+ (List.length targets)
+ | Some uuids, _ -> uuids
+ | None, uuids -> uuids in
+ assert (List.length image_uuids = List.length targets);
(* The storage domain UUID. *)
let sd_uuid =
@@ -411,7 +444,7 @@ If the messages above are not sufficient to diagnose the problem then add the
let ovf =
Create_ovf.create_ovf source targets guestcaps inspect
target_firmware output_alloc
- sd_uuid disks_uuids vol_uuids vm_uuid
+ sd_uuid image_uuids vol_uuids vm_uuid
OVirt in
let ovf = DOM.doc_to_string ovf in
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index 4d61a089b..6ec74a5d4 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -135,6 +135,8 @@ def open(readonly):
disk_format = types.DiskFormat.COW
disk = disks_service.add(
disk = types.Disk(
+ # The ID is optional.
+ id = params.get('rhv_disk_uuid'),
name = params['disk_name'],
description = "Uploaded by virt-v2v",
format = disk_format,
diff --git a/v2v/virt-v2v-output-rhv.pod b/v2v/virt-v2v-output-rhv.pod
index 651f61dae..e840ca78d 100644
--- a/v2v/virt-v2v-output-rhv.pod
+++ b/v2v/virt-v2v-output-rhv.pod
@@ -9,6 +9,7 @@ virt-v2v-output-rhv - Using virt-v2v to convert guests to oVirt or RHV
[-oo rhv-cafile=FILE]
[-oo rhv-cluster=CLUSTER]
[-oo rhv-direct]
+ [-oo rhv-disk-uuid=UUID ...]
[-oo rhv-verifypeer]
virt-v2v [-i* options] -o rhv -os [esd:/path|/path]
@@ -104,6 +105,29 @@ F</etc/pki/ovirt-engine/ca.pem> on the oVirt engine.
Set the RHV Cluster Name. If not given it uses C<Default>.
+=item I<-oo rhv-disk-uuid=>C<UUID>
+
+This option can used to manually specify UUIDs for the disks when
+creating the virtual machine. If not specified, the oVirt engine will
+generate random UUIDs for the disks. Please note that:
+
+=over 4
+
+=item *
+
+you B<must> pass as many I<-oo rhv-disk-uuid=UUID> options as the
+amount of disks in the guest
+
+=item *
+
+the specified UUIDs are used as they are, without checking whether
+they are already used by other disks
+
+=back
+
+This option is considered advanced, and to be used mostly in
+combination with I<--no-copy>.
+
=item I<-oo rhv-direct>
If this option is given then virt-v2v will attempt to directly upload
--
2.26.2

View File

@ -1,29 +0,0 @@
From da504873e18fc1414d670f318c10d5fb512e05dd Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Fri, 29 Jun 2018 12:58:33 +0200
Subject: [PATCH] v2v: improve -os documentation for rhv-upload
Thanks to: Ming Xie
(cherry picked from commit 8d33ff8ba415180dee8f1f91f3b4d16d72ec094e)
---
v2v/virt-v2v.pod | 3 +++
1 file changed, 3 insertions(+)
diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
index f012ea533..893e47fb9 100644
--- a/v2v/virt-v2v.pod
+++ b/v2v/virt-v2v.pod
@@ -758,6 +758,9 @@ For I<-o libvirt>, this is a libvirt directory pool
For I<-o local> and I<-o qemu>, this is a directory name. The
directory must exist.
+For I<-o rhv-upload>, this is the name of the destination Storage
+Domain.
+
For I<-o rhv>, this can be an NFS path of the Export Storage Domain
of the form C<E<lt>hostE<gt>:E<lt>pathE<gt>>, eg:
--
2.21.0

View File

@ -0,0 +1,87 @@
From 5ad1e7c160f5fe0d499d8d25116cb0e1692f1e93 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Fri, 27 Sep 2019 13:56:42 +0200
Subject: [PATCH] v2v: -o rhv-upload: make -oo rhv-cafile optional
It makes little sense to require the oVirt certificate, especially when
the verification of the connection (-oo rhv-verifypeer) is disabled by
default. The only work done with the certificate in that case is
checking that it is a valid certificate file.
Hence, make -oo rhv-cafile optional, requiring it only when
-oo rhv-verifypeer is enabled.
(cherry picked from commit 0a5eaad7db3c9b9a03fa88102a9e6142c855bfd1)
---
v2v/output_rhv_upload.ml | 16 +++++++++-------
v2v/virt-v2v-output-rhv.pod | 2 ++
2 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml
index 206657a2b..2c8c18732 100644
--- a/v2v/output_rhv_upload.ml
+++ b/v2v/output_rhv_upload.ml
@@ -28,7 +28,7 @@ open Types
open Utils
type rhv_options = {
- rhv_cafile : string;
+ rhv_cafile : string option;
rhv_cluster : string option;
rhv_direct : bool;
rhv_verifypeer : bool;
@@ -76,15 +76,13 @@ let parse_output_options options =
error (f_"-o rhv-upload: unknown output option -oo %s") k
) options;
- let rhv_cafile =
- match !rhv_cafile with
- | Some s -> s
- | None ->
- error (f_"-o rhv-upload: must use -oo rhv-cafile to supply the path to the oVirt or RHV users ca.pem file") in
+ let rhv_cafile = !rhv_cafile in
let rhv_cluster = !rhv_cluster in
let rhv_direct = !rhv_direct in
let rhv_verifypeer = !rhv_verifypeer in
let rhv_disk_uuids = Option.map List.rev !rhv_disk_uuids in
+ if rhv_verifypeer && rhv_cafile = None then
+ error (f_"-o rhv-upload: must use -oo rhv-cafile to supply the path to the oVirt or RHV users ca.pem file");
{ rhv_cafile; rhv_cluster; rhv_direct; rhv_verifypeer; rhv_disk_uuids }
@@ -92,6 +90,10 @@ let nbdkit_python_plugin = Config.virt_v2v_nbdkit_python_plugin
let pidfile_timeout = 30
let finalization_timeout = 5*60
+let json_optstring = function
+ | Some s -> JSON.String s
+ | None -> JSON.Null
+
class output_rhv_upload output_alloc output_conn
output_password output_storage
rhv_options =
@@ -200,7 +202,7 @@ See also the virt-v2v-output-rhv(1) manual.")
"output_sparse", JSON.Bool (match output_alloc with
| Sparse -> true
| Preallocated -> false);
- "rhv_cafile", JSON.String rhv_options.rhv_cafile;
+ "rhv_cafile", json_optstring rhv_options.rhv_cafile;
"rhv_cluster",
JSON.String (Option.default "Default" rhv_options.rhv_cluster);
"rhv_direct", JSON.Bool rhv_options.rhv_direct;
diff --git a/v2v/virt-v2v-output-rhv.pod b/v2v/virt-v2v-output-rhv.pod
index e840ca78d..04a894268 100644
--- a/v2v/virt-v2v-output-rhv.pod
+++ b/v2v/virt-v2v-output-rhv.pod
@@ -101,6 +101,8 @@ The storage domain.
The F<ca.pem> file (Certificate Authority), copied from
F</etc/pki/ovirt-engine/ca.pem> on the oVirt engine.
+This option must be specified if I<-oo rhv-verifypeer> is enabled.
+
=item I<-oo rhv-cluster=>C<CLUSTERNAME>
Set the RHV Cluster Name. If not given it uses C<Default>.
--
2.26.2

View File

@ -0,0 +1,40 @@
From 1b409cee748cfb60cc87f8bfa80370048d8dd014 Mon Sep 17 00:00:00 2001
From: Mike Latimer <mlatimer@suse.com>
Date: Mon, 25 Mar 2019 14:38:00 +0000
Subject: [PATCH] v2v: Fix default graphics driver for SUSE guests.
See discussion in this upstream thread:
https://www.redhat.com/archives/libguestfs/2019-February/thread.html#00047
Thanks: Mike Latimer, Pino Toscano.
(cherry picked from commit 612f170e6062f2ff74643b6096b7e0765b52cfbd)
---
v2v/convert_linux.ml | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml
index b4b2f24c4..f9e811c8d 100644
--- a/v2v/convert_linux.ml
+++ b/v2v/convert_linux.ml
@@ -104,7 +104,7 @@ let convert (g : G.guestfs) inspect source output rcaps =
let video =
match rcaps.rcaps_video with
- | None -> get_display_driver ()
+ | None -> QXL
| Some video -> video in
let block_type =
@@ -783,9 +783,6 @@ let convert (g : G.guestfs) inspect source output rcaps =
else
true
- and get_display_driver () =
- if family = `SUSE_family then Cirrus else QXL
-
and configure_display_driver video =
let video_driver = match video with QXL -> "qxl" | Cirrus -> "cirrus" in
--
2.26.2

View File

@ -1,69 +0,0 @@
From a3e99c84e1aed2fc275be00292f86414c8d4432a Mon Sep 17 00:00:00 2001
From: Nir Soffer <nirsof@gmail.com>
Date: Fri, 29 Jun 2018 17:41:10 +0300
Subject: [PATCH] v2v: rhv-upload-plugin: Remove unneeded auth
Old imageio proxy was using Authorization header for GET and PUT
requests. Remove unneeded authorization when sending OPTIONS request.
Remove unneeded duplicated comments about authorization for old
imageio, and replace them with a comment when we set needs_auth.
(cherry picked from commit d5f36bacf9bb6d4d244184551792989906f60896)
---
v2v/rhv-upload-plugin.py | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index 8805e3552..f404bd758 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -191,16 +191,17 @@ def open(readonly):
)
# The first request is to fetch the features of the server.
+
+ # Authentication was needed only for GET and PUT requests when
+ # communicating with old imageio-proxy.
needs_auth = not params['rhv_direct']
+
can_flush = False
can_trim = False
can_zero = False
unix_socket = None
- http.putrequest("OPTIONS", destination_url.path)
- http.putheader("Authorization", transfer.signed_ticket)
- http.endheaders()
-
+ http.request("OPTIONS", destination_url.path)
r = http.getresponse()
data = r.read()
@@ -298,7 +299,6 @@ def pread(h, count, offset):
transfer = h['transfer']
headers = {"Range", "bytes=%d-%d" % (offset, offset+count-1)}
- # Authorization is only needed for old imageio.
if h['needs_auth']:
headers["Authorization"] = transfer.signed_ticket
@@ -321,7 +321,6 @@ def pwrite(h, buf, offset):
h['highestwrite'] = max(h['highestwrite'], offset+count)
http.putrequest("PUT", h['path'] + "?flush=n")
- # Authorization is only needed for old imageio.
if h['needs_auth']:
http.putheader("Authorization", transfer.signed_ticket)
# The oVirt server only uses the first part of the range, and the
@@ -378,7 +377,6 @@ def emulate_zero(h, count, offset):
# After that we must emulate them with writes.
if offset+count < h['highestwrite']:
http.putrequest("PUT", h['path'])
- # Authorization is only needed for old imageio.
if h['needs_auth']:
http.putheader("Authorization", transfer.signed_ticket)
http.putheader("Content-Range",
--
2.21.0

View File

@ -1,66 +0,0 @@
From 8aaf7d89ef8b686840d3683fb27c4746624088a5 Mon Sep 17 00:00:00 2001
From: Nir Soffer <nirsof@gmail.com>
Date: Sat, 30 Jun 2018 01:21:50 +0300
Subject: [PATCH] v2v: rhv-upload-plugin: Improve error handling
When optimizing the connection using unix socket, we handle these cases:
- The local host is not an oVirt host (no /etc/vdsm/vdsm.id).
- The local host is an oVirt host, but is not registered with engine.
- Creating UnixHTTPConnection() fails. Unlikely and probably a bug in
the plugin, but we can recover by using the https connection.
The current code handle these cases silently, making it harder to
understand why the unix socket optimization did no happen. Add debug
message to make this clear.
Also comment in the error handler why we take this path instead of
failing the operation.
(cherry picked from commit f5442d2f044b398efc992fb4d56c8d3096c781e6)
---
v2v/rhv-upload-plugin.py | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index f404bd758..8e4052048 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -63,7 +63,10 @@ def find_host(connection):
with builtins.open("/etc/vdsm/vdsm.id") as f:
vdsm_id = f.readline().strip()
except Exception as e:
+ # This is most likely not an oVirt host.
+ debug("cannot read /etc/vdsm/vdsm.id, using any host: %s" % e)
return None
+
debug("hw_id = %r" % vdsm_id)
hosts_service = connection.system_service().hosts_service()
@@ -72,6 +75,8 @@ def find_host(connection):
case_sensitive=False,
)
if len(hosts) == 0:
+ # This oVirt host is not registered with engine.
+ debug("cannot find host with hw_id=%r, using any host" % vdsm_id)
return None
host = hosts[0]
@@ -233,9 +238,12 @@ def open(readonly):
if host is not None and unix_socket is not None:
try:
http = UnixHTTPConnection(unix_socket)
+ except Exception as e:
+ # Very unlikely failure, but we can recover by using the https
+ # connection.
+ debug("cannot create unix socket connection, using https: %s" % e)
+ else:
debug("optimizing connection using unix socket %r" % unix_socket)
- except:
- pass
# Save everything we need to make requests in the handle.
return {
--
2.21.0

View File

@ -0,0 +1,73 @@
From bb09f8b1ab0fc3bda654e7d564d5010f9f24f660 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 4 Dec 2018 16:09:42 +0000
Subject: [PATCH] v2v: windows: Add a helper function for installing Powershell
firstboot scripts.
(cherry picked from commit e1e9b3845e76a4bb406d16b96283ac38677cd91f)
---
v2v/Makefile.am | 1 +
v2v/windows.ml | 23 +++++++++++++++++++++++
v2v/windows.mli | 6 ++++++
3 files changed, 30 insertions(+)
diff --git a/v2v/Makefile.am b/v2v/Makefile.am
index 30f040d3e..6568c9a6b 100644
--- a/v2v/Makefile.am
+++ b/v2v/Makefile.am
@@ -667,6 +667,7 @@ check_PROGRAMS += v2v_unit_tests var_expander_tests
endif
v2v_unit_tests_BOBJECTS = \
+ $(top_builddir)/customize/firstboot.cmo \
types.cmo \
uefi.cmo \
utils.cmo \
diff --git a/v2v/windows.ml b/v2v/windows.ml
index 23d589b00..d83f77b7f 100644
--- a/v2v/windows.ml
+++ b/v2v/windows.ml
@@ -45,3 +45,26 @@ and check_app { Guestfs.app2_name = name;
publisher =~ rex_avg_tech
and (=~) str rex = PCRE.matches rex str
+
+(* Unfortunately Powershell scripts cannot be directly executed
+ * (unless some system config changes are made which for other
+ * reasons we don't want to do) and so we have to run this via
+ * a regular batch file.
+ *)
+let install_firstboot_powershell g { Types.i_windows_systemroot; i_root }
+ filename code =
+ let tempdir = sprintf "%s/Temp" i_windows_systemroot in
+ g#mkdir_p tempdir;
+ let code = String.concat "\r\n" code ^ "\r\n" in
+ g#write (sprintf "%s/%s" tempdir filename) code;
+
+ (* Powershell interpreter. Should we check this exists? XXX *)
+ let ps_exe =
+ i_windows_systemroot ^
+ "\\System32\\WindowsPowerShell\\v1.0\\powershell.exe" in
+
+ (* Windows path to the Powershell script. *)
+ let ps_path = i_windows_systemroot ^ "\\Temp\\" ^ filename in
+
+ let fb = sprintf "%s -ExecutionPolicy ByPass -file %s" ps_exe ps_path in
+ Firstboot.add_firstboot_script g i_root filename fb
diff --git a/v2v/windows.mli b/v2v/windows.mli
index 016ef2a78..6db7874b0 100644
--- a/v2v/windows.mli
+++ b/v2v/windows.mli
@@ -21,3 +21,9 @@
val detect_antivirus : Types.inspect -> bool
(** Return [true] if anti-virus (AV) software was detected in
this Windows guest. *)
+
+val install_firstboot_powershell : Guestfs.guestfs -> Types.inspect ->
+ string -> string list -> unit
+(** [install_powershell_firstboot g inspect filename code] installs a
+ Powershell script (the lines of code) as a firstboot script in
+ the Windows VM. *)
--
2.26.2

View File

@ -0,0 +1,423 @@
From 70e2215cd1f660dbad5a336bb611ad1b9cf1e60d Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 4 Dec 2018 16:09:42 +0000
Subject: [PATCH] v2v: Copy static IP address information over for Windows
guests (RHBZ#1626503).
For Linux the guest itself remembers the IP address associated with
each MAC address. Thus it doesn't matter if the interface type
changes (ie. to virtio-net), because as long as we preserve the MAC
address the guest will use the same IP address or the same DHCP
configuration.
However on Windows this association is not maintained by MAC address.
In fact the MAC address isn't saved anywhere in the guest registry.
(It seems instead this is likely done through PCI device type and
address which we don't record at the moment and is almost impossible
to preserve.) When a guest which doesn't use DHCP is migrated, the
guest sees the brand new virtio-net devices and doesn't know what to
do with them, and meanwhile the right static IPs are still associated
with the old and now-defunct interfaces in the registry.
We cannot collect the required information from within the guest.
However we can collect it outside the tool by some other means
(eg. using VMware Tools APIs) and present this information to virt-v2v
which then writes it into the Windows guest at firstboot time.
This commit adds the --mac ..:ip:.. sub-option which creates a
Powershell script to set network adapters at firstboot. An option
such as:
--mac 00:0c:29:e6:3d:9d:ip:192.168.0.89,192.168.0.1,24,192.168.0.254
approximately turns into this script:
# Wait for the netkvm (virtio-net) driver to become active.
$adapters = @()
While (-Not $adapters) {
Start-Sleep -Seconds 5
$adapters = Get-NetAdapter -Physical |
Where DriverFileName -eq "netkvm.sys"
}
$mac_address = '00-0c-29-e6-3d-9d'
$ifindex = (Get-NetAdapter -Physical |
Where MacAddress -eq $mac_address).ifIndex
if ($ifindex) {
New-NetIPAddress -InterfaceIndex $ifindex
-IPAddress '192.168.0.89'
-DefaultGateway '192.168.0.1'
-PrefixLength 24
Set-DnsClientServerAddress -InterfaceIndex $ifindex
-ServerAddresses ('192.168.0.254')
}
Thanks: Brett Thurber for diagnosing the problem and suggesting paths
towards a fix.
(cherry picked from commit dfd9fac7435cf2f9293961b6cc1fe316af4feebc)
---
v2v/cmdline.ml | 41 ++++++++++++++++++-----
v2v/cmdline.mli | 1 +
v2v/convert_linux.ml | 2 +-
v2v/convert_windows.ml | 76 +++++++++++++++++++++++++++++++++++++++++-
v2v/modules_list.ml | 2 +-
v2v/modules_list.mli | 2 +-
v2v/types.ml | 8 +++++
v2v/types.mli | 9 +++++
v2v/v2v.ml | 7 ++--
v2v/virt-v2v.pod | 18 ++++++++++
10 files changed, 150 insertions(+), 16 deletions(-)
diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
index 4d390f249..686631271 100644
--- a/v2v/cmdline.ml
+++ b/v2v/cmdline.ml
@@ -40,11 +40,12 @@ type cmdline = {
print_estimate : bool;
print_source : bool;
root_choice : root_choice;
+ static_ips : static_ip list;
ks : Tools_utils.key_store;
}
(* Matches --mac command line parameters. *)
-let mac_re = PCRE.compile ~anchored:true "([[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}):(network|bridge):(.*)"
+let mac_re = PCRE.compile ~anchored:true "([[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}):(network|bridge|ip):(.*)"
let parse_cmdline () =
let compressed = ref false in
@@ -97,6 +98,7 @@ let parse_cmdline () =
in
let network_map = Networks.create () in
+ let static_ips = ref [] in
let add_network str =
match String.split ":" str with
| "", "" ->
@@ -119,11 +121,30 @@ let parse_cmdline () =
if not (PCRE.matches mac_re str) then
error (f_"cannot parse --mac \"%s\" parameter") str;
let mac = PCRE.sub 1 and out = PCRE.sub 3 in
- let vnet_type =
- match PCRE.sub 2 with
- | "network" -> Network | "bridge" -> Bridge
- | _ -> assert false in
- Networks.add_mac network_map mac vnet_type out
+ match PCRE.sub 2 with
+ | "network" ->
+ Networks.add_mac network_map mac Network out
+ | "bridge" ->
+ Networks.add_mac network_map mac Bridge out
+ | "ip" ->
+ let add if_mac_addr if_ip_address if_default_gateway
+ if_prefix_length if_nameservers =
+ List.push_back static_ips
+ { if_mac_addr; if_ip_address; if_default_gateway;
+ if_prefix_length; if_nameservers }
+ in
+ (match String.nsplit "," out with
+ | [] ->
+ error (f_"invalid --mac ip option")
+ | [ip] -> add mac ip None None []
+ | [ip; gw] -> add mac ip (Some gw) None []
+ | ip :: gw :: len :: nameservers ->
+ let len =
+ try int_of_string len with
+ | Failure _ -> error (f_"cannot parse --mac ip prefix length field as an integer: %s") len in
+ add mac ip (Some gw) (Some len) nameservers
+ );
+ | _ -> assert false
in
let no_trim_warning _ =
@@ -211,8 +232,8 @@ let parse_cmdline () =
s_"Input transport";
[ L"in-place" ], Getopt.Set in_place,
s_"Only tune the guest in the input VM";
- [ L"mac" ], Getopt.String ("mac:network|bridge:out", add_mac),
- s_"Map NIC to network or bridge";
+ [ L"mac" ], Getopt.String ("mac:network|bridge|ip:out", add_mac),
+ s_"Map NIC to network or bridge or assign static IP";
[ S 'n'; L"network" ], Getopt.String ("in:out", add_network),
s_"Map network in to out";
[ L"no-copy" ], Getopt.Clear do_copy,
@@ -335,6 +356,7 @@ read the man page virt-v2v(1).
let print_source = !print_source in
let qemu_boot = !qemu_boot in
let root_choice = !root_choice in
+ let static_ips = !static_ips in
(* No arguments and machine-readable mode? Print out some facts
* about what this binary supports.
@@ -351,6 +373,7 @@ read the man page virt-v2v(1).
pr "in-place\n";
pr "io/oo\n";
pr "mac-option\n";
+ pr "mac-ip-option\n";
List.iter (pr "input:%s\n") (Modules_list.input_modules ());
List.iter (pr "output:%s\n") (Modules_list.output_modules ());
List.iter (pr "convert:%s\n") (Modules_list.convert_modules ());
@@ -685,7 +708,7 @@ read the man page virt-v2v(1).
{
compressed; debug_overlays; do_copy; in_place; network_map;
output_alloc; output_format; output_name;
- print_estimate; print_source; root_choice;
+ print_estimate; print_source; root_choice; static_ips;
ks = opthandle.ks;
},
input, output
diff --git a/v2v/cmdline.mli b/v2v/cmdline.mli
index 78601e191..a009e9888 100644
--- a/v2v/cmdline.mli
+++ b/v2v/cmdline.mli
@@ -30,6 +30,7 @@ type cmdline = {
print_estimate : bool;
print_source : bool;
root_choice : Types.root_choice;
+ static_ips : Types.static_ip list;
ks : Tools_utils.key_store;
}
diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml
index f9e811c8d..1ada36115 100644
--- a/v2v/convert_linux.ml
+++ b/v2v/convert_linux.ml
@@ -34,7 +34,7 @@ open Linux_kernels
module G = Guestfs
(* The conversion function. *)
-let convert (g : G.guestfs) inspect source output rcaps =
+let convert (g : G.guestfs) inspect source output rcaps _ =
(*----------------------------------------------------------------------*)
(* Inspect the guest first. We already did some basic inspection in
* the common v2v.ml code, but that has to deal with generic guests
diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml
index 1db3c0ea6..75e609d61 100644
--- a/v2v/convert_windows.ml
+++ b/v2v/convert_windows.ml
@@ -38,7 +38,7 @@ module G = Guestfs
* time the Windows VM is booted on KVM.
*)
-let convert (g : G.guestfs) inspect source output rcaps =
+let convert (g : G.guestfs) inspect source output rcaps static_ips =
(*----------------------------------------------------------------------*)
(* Inspect the Windows guest. *)
@@ -228,6 +228,8 @@ let convert (g : G.guestfs) inspect source output rcaps =
Registry.with_hive_write g inspect.i_windows_software_hive
update_software_hive;
+ configure_network_interfaces net_driver;
+
fix_ntfs_heads ();
fix_win_esp ();
@@ -603,6 +605,78 @@ if errorlevel 3010 exit /b 0
| None ->
warning (f_"could not find registry key HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion")
+ and configure_network_interfaces net_driver =
+ (* If we were asked to force network interfaces to have particular
+ * static IP addresses then it is done here by installing a
+ * Powershell script which runs at boot.
+ *)
+ if static_ips <> [] then (
+ let psh_filename = "v2vnetcf.ps1" in
+ let psh = ref [] in
+ let add = List.push_back psh in
+
+ add "# Uncomment this line for lots of debug output.";
+ add "# Set-PSDebug -Trace 1";
+ add "";
+
+ (* If virtio-net was added to the registry, we must wait for
+ * it to be installed at runtime.
+ *)
+ if net_driver = Virtio_net then (
+ add "# Wait for the netkvm (virtio-net) driver to become active.";
+ add "$adapters = @()";
+ add "While (-Not $adapters) {";
+ add " Start-Sleep -Seconds 5";
+ add " $adapters = Get-NetAdapter -Physical | Where DriverFileName -eq \"netkvm.sys\"";
+ add " Write-Host \"adapters = '$adapters'\"";
+ add "}";
+ add ""
+ );
+
+ List.iter (
+ fun { if_mac_addr; if_ip_address; if_default_gateway;
+ if_prefix_length; if_nameservers } ->
+ add (sprintf "$mac_address = '%s'"
+ (String.replace if_mac_addr ":" "-"));
+ add "$ifindex = (Get-NetAdapter -Physical | Where MacAddress -eq $mac_address).ifIndex";
+ add "if ($ifindex) {";
+
+ add " Write-Host \"setting IP address of adapter at $ifindex\"";
+
+ (* New-NetIPAddress command *)
+ let args = ref [] in
+ List.push_back args "-InterfaceIndex";
+ List.push_back args "$ifindex";
+ List.push_back args "-IPAddress";
+ List.push_back args (sprintf "'%s'" if_ip_address);
+ (match if_default_gateway with
+ | None -> ()
+ | Some gw ->
+ List.push_back args "-DefaultGateway";
+ List.push_back args (sprintf "'%s'" gw)
+ );
+ (match if_prefix_length with
+ | None -> ()
+ | Some len ->
+ List.push_back args "-PrefixLength";
+ List.push_back args (string_of_int len)
+ );
+ let cmd1 = "New-NetIPAddress " ^ String.concat " " !args in
+ add (" " ^ cmd1);
+
+ (* Set-DnsClientServerAddress command *)
+ if if_nameservers <> [] then (
+ add (sprintf " Set-DnsClientServerAddress -InterfaceIndex $ifindex -ServerAddresses (%s)"
+ (String.concat "," (List.map (sprintf "'%s'") if_nameservers)))
+ );
+ add "}";
+ add ""
+ ) static_ips;
+
+ (* Install the Powershell script to run at firstboot. *)
+ Windows.install_firstboot_powershell g inspect psh_filename !psh
+ ) (* static_ips <> [] *)
+
and fix_ntfs_heads () =
(* NTFS hardcodes the number of heads on the drive which created
it in the filesystem header. Modern versions of Windows
diff --git a/v2v/modules_list.ml b/v2v/modules_list.ml
index a0a74aaf2..76b3def5d 100644
--- a/v2v/modules_list.ml
+++ b/v2v/modules_list.ml
@@ -38,7 +38,7 @@ type inspection_fn = Types.inspect -> bool
type conversion_fn =
Guestfs.guestfs -> Types.inspect -> Types.source -> Types.output_settings ->
- Types.requested_guestcaps -> Types.guestcaps
+ Types.requested_guestcaps -> Types.static_ip list -> Types.guestcaps
let convert_modules = ref []
diff --git a/v2v/modules_list.mli b/v2v/modules_list.mli
index 3e80d3e23..ad2024755 100644
--- a/v2v/modules_list.mli
+++ b/v2v/modules_list.mli
@@ -34,7 +34,7 @@ type inspection_fn = Types.inspect -> bool
type conversion_fn =
Guestfs.guestfs -> Types.inspect -> Types.source -> Types.output_settings ->
- Types.requested_guestcaps -> Types.guestcaps
+ Types.requested_guestcaps -> Types.static_ip list -> Types.guestcaps
val register_convert_module : inspection_fn -> string -> conversion_fn -> unit
(** [register_convert_module inspect_fn name fn] registers a
diff --git a/v2v/types.ml b/v2v/types.ml
index 714b30014..4ba6117fd 100644
--- a/v2v/types.ml
+++ b/v2v/types.ml
@@ -506,6 +506,14 @@ type root_choice = AskRoot | SingleRoot | FirstRoot | RootDev of string
type output_allocation = Sparse | Preallocated
+type static_ip = {
+ if_mac_addr : string;
+ if_ip_address : string;
+ if_default_gateway : string option;
+ if_prefix_length : int option;
+ if_nameservers : string list;
+}
+
class virtual input = object
method precheck () = ()
method virtual as_options : string
diff --git a/v2v/types.mli b/v2v/types.mli
index f595ab0ef..528d77965 100644
--- a/v2v/types.mli
+++ b/v2v/types.mli
@@ -361,6 +361,15 @@ type root_choice = AskRoot | SingleRoot | FirstRoot | RootDev of string
type output_allocation = Sparse | Preallocated
(** Type of [-oa] (output allocation) option. *)
+type static_ip = {
+ if_mac_addr : string;
+ if_ip_address : string;
+ if_default_gateway : string option;
+ if_prefix_length : int option;
+ if_nameservers : string list;
+}
+(** [--mac ..:ip:..] option. *)
+
(** {2 Input object}
This is subclassed for the various input [-i] options.
diff --git a/v2v/v2v.ml b/v2v/v2v.ml
index 63e809030..d7a868659 100644
--- a/v2v/v2v.ml
+++ b/v2v/v2v.ml
@@ -133,7 +133,7 @@ let rec main () =
| In_place ->
rcaps_from_source source in
- do_convert g inspect source output rcaps in
+ do_convert g inspect source output rcaps cmdline.static_ips in
g#umount_all ();
@@ -556,7 +556,7 @@ and estimate_target_size mpstats overlays =
)
(* Conversion. *)
-and do_convert g inspect source output rcaps =
+and do_convert g inspect source output rcaps interfaces =
(match inspect.i_product_name with
| "unknown" ->
message (f_"Converting the guest to run on KVM")
@@ -572,7 +572,8 @@ and do_convert g inspect source output rcaps =
debug "picked conversion module %s" conversion_name;
debug "requested caps: %s" (string_of_requested_guestcaps rcaps);
let guestcaps =
- convert g inspect source (output :> Types.output_settings) rcaps in
+ convert g inspect source (output :> Types.output_settings) rcaps
+ interfaces in
debug "%s" (string_of_guestcaps guestcaps);
(* Did we manage to install virtio drivers? *)
diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
index 9a555c3be..0642d158f 100644
--- a/v2v/virt-v2v.pod
+++ b/v2v/virt-v2v.pod
@@ -368,6 +368,24 @@ Map source NIC MAC address to a network or bridge.
See L</Networks and bridges> below.
+=item B<--mac> aa:bb:cc:dd:ee:ffB<:ip:>ipaddr[,gw[,len[,ns,ns,...]]]
+
+Force a particular interface (controlled by its MAC address) to have a
+static IP address after boot.
+
+The fields in the parameter are: C<ipaddr> is the IP address. C<gw>
+is the optional gateway IP address. C<len> is the subnet mask length
+(an integer). The final parameters are zero or more nameserver IP
+addresses.
+
+This option can be supplied zero or more times.
+
+You only need to use this option for certain broken guests such as
+Windows which are unable to preserve MAC to static IP address mappings
+automatically. You don't need to use it if Windows is using DHCP. It
+is currently ignored for Linux guests since they do not have this
+problem.
+
=item B<--machine-readable>
=item B<--machine-readable>=format
--
2.26.2

View File

@ -1,32 +0,0 @@
From 7b5ec5a6478276cec587c7d6a64b9a1ab26447b2 Mon Sep 17 00:00:00 2001
From: Nir Soffer <nirsof@gmail.com>
Date: Sat, 30 Jun 2018 01:39:03 +0300
Subject: [PATCH] v2v: rhv-upload-plugin: Optimize only direct upload
The optimization to start the transfer on the local host makes sense
only when using the rhv-direct=true option. When using a proxy, let the
engine choose a host.
(cherry picked from commit 891b5a0ec0f320acec0f06b64159eaf3dfbbfeaf)
---
v2v/rhv-upload-plugin.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index 8e4052048..da309e288 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -148,8 +148,8 @@ def open(readonly):
# Get a reference to the transfer service.
transfers_service = system_service.image_transfers_service()
- # Create a new image transfer.
- host = find_host(connection)
+ # Create a new image transfer, using the local host is possible.
+ host = find_host(connection) if params['rhv_direct'] else None
transfer = transfers_service.add(
types.ImageTransfer(
disk = types.Disk(id = disk.id),
--
2.21.0

View File

@ -0,0 +1,87 @@
From bcd376966fedca02a52ad61405e84de931a89899 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Fri, 29 Nov 2019 11:48:59 +0100
Subject: [PATCH] New API: luks_uuid
Return the UUID of a LUKS device.
(cherry picked from commit 206ce8bbf1bc3332dc019e553d17d6a36f74b725)
---
daemon/luks.c | 25 +++++++++++++++++++++++++
generator/actions_core.ml | 8 ++++++++
generator/proc_nr.ml | 1 +
lib/MAX_PROC_NR | 2 +-
4 files changed, 35 insertions(+), 1 deletion(-)
diff --git a/daemon/luks.c b/daemon/luks.c
index 5c48a91eb..d631cb100 100644
--- a/daemon/luks.c
+++ b/daemon/luks.c
@@ -292,3 +292,28 @@ do_luks_kill_slot (const char *device, const char *key, int keyslot)
return 0;
}
+
+char *
+do_luks_uuid (const char *device)
+{
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+
+ ADD_ARG (argv, i, "cryptsetup");
+ ADD_ARG (argv, i, "luksUUID");
+ ADD_ARG (argv, i, device);
+ ADD_ARG (argv, i, NULL);
+
+ char *out = NULL;
+ CLEANUP_FREE char *err = NULL;
+ int r = commandv (&out, &err, (const char * const *) argv);
+
+ if (r == -1) {
+ reply_with_error ("%s", err);
+ return NULL;
+ }
+
+ trim (out);
+
+ return out;
+}
diff --git a/generator/actions_core.ml b/generator/actions_core.ml
index 7b6568b90..deda483a9 100644
--- a/generator/actions_core.ml
+++ b/generator/actions_core.ml
@@ -9728,4 +9728,12 @@ it is useful when you have added a new device or deleted an
existing device (such as when the C<guestfs_luks_open> API
is used)." };
+ { defaults with
+ name = "luks_uuid"; added = (1, 41, 9);
+ style = RString (RPlainString, "uuid"), [String (Device, "device")], [];
+ optional = Some "luks";
+ shortdesc = "get the UUID of a LUKS device";
+ longdesc = "\
+This returns the UUID of the LUKS device C<device>." };
+
]
diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml
index efa8c5d21..11a557076 100644
--- a/generator/proc_nr.ml
+++ b/generator/proc_nr.ml
@@ -514,6 +514,7 @@ let proc_nr = [
504, "part_get_gpt_attributes";
505, "f2fs_expand";
506, "lvm_scan";
+507, "luks_uuid";
]
(* End of list. If adding a new entry, add it at the end of the list
diff --git a/lib/MAX_PROC_NR b/lib/MAX_PROC_NR
index 80e3e6eab..055b6671a 100644
--- a/lib/MAX_PROC_NR
+++ b/lib/MAX_PROC_NR
@@ -1 +1 @@
-506
+507
--
2.26.2

View File

@ -1,61 +0,0 @@
From e1401de974b6ac6d3e6e94e774f24a9b74f806f2 Mon Sep 17 00:00:00 2001
From: Daniel Erez <derez@redhat.com>
Date: Thu, 5 Jul 2018 20:23:35 +0300
Subject: [PATCH] v2v: rhv plugin - find suitable host (RHBZ#1596810)
(RHBZ#1596851)
For direct upload, a suitable host must be in status 'Up'
and belong to the same datacenter as the created disk.
Added these criteria to the host search query.
(cherry picked from commit 4ed1bc5a79a77ad3a620b339f9ac2ecc8df6fd03)
---
v2v/rhv-upload-plugin.py | 28 ++++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index da309e288..931fcfaa2 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -69,14 +69,34 @@ def find_host(connection):
debug("hw_id = %r" % vdsm_id)
- hosts_service = connection.system_service().hosts_service()
+ system_service = connection.system_service()
+ storage_name = params['output_storage']
+ data_centers = system_service.data_centers_service().list(
+ search='storage=%s' % storage_name,
+ case_sensitive=False,
+ )
+ if len(data_centers) == 0:
+ # The storage domain is not attached to a datacenter
+ # (shouldn't happen, would fail on disk creation).
+ debug("storange domain (%s) is not attached to a DC" % storage_name)
+ return None
+
+ datacenter = data_centers[0]
+ debug("datacenter = %s" % datacenter.name)
+
+ hosts_service = system_service.hosts_service()
hosts = hosts_service.list(
- search="hw_id=%s" % vdsm_id,
+ search="hw_id=%s and datacenter=%s and status=Up" % (vdsm_id, datacenter.name),
case_sensitive=False,
)
if len(hosts) == 0:
- # This oVirt host is not registered with engine.
- debug("cannot find host with hw_id=%r, using any host" % vdsm_id)
+ # Couldn't find a host that's fulfilling the following criteria:
+ # - 'hw_id' equals to 'vdsm_id'
+ # - Its status is 'Up'
+ # - Belongs to the storage domain's datacenter
+ debug("cannot find a running host with hw_id=%r, " \
+ "that belongs to datacenter '%s', " \
+ "using any host" % (vdsm_id, datacenter.name))
return None
host = hosts[0]
--
2.21.0

View File

@ -0,0 +1,47 @@
From 7f12a3ddad2b735dc6d06b7b3ef67aacc57defe2 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 12 Nov 2019 18:15:44 +0000
Subject: [PATCH] options: Fix segfault when multiple --key parameters given.
Easily reproducible using:
$ guestfish --key dev1:key:key1 --key dev2:key:key2
causing this stack trace (or others depending on where the memory
corruption was caught):
Program received signal SIGABRT, Aborted.
0x00007ffff7905625 in raise () from /lib64/libc.so.6
(gdb) bt
#0 0x00007ffff7905625 in raise () from /lib64/libc.so.6
#1 0x00007ffff78ee8d9 in abort () from /lib64/libc.so.6
#2 0x00007ffff79494af in __libc_message () from /lib64/libc.so.6
#3 0x00007ffff7950a6c in malloc_printerr () from /lib64/libc.so.6
#4 0x00007ffff79528d0 in _int_free () from /lib64/libc.so.6
#5 0x00005555555bdd6e in free_key_store ()
#6 0x0000555555589027 in main ()
(gdb) quit
(cherry picked from commit 8c42f772614b44a8cb974afa904ec9f518431ab2
in libguestfs-common)
---
common/options/keys.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/common/options/keys.c b/common/options/keys.c
index 7f689866b..f783066ff 100644
--- a/common/options/keys.c
+++ b/common/options/keys.c
@@ -216,7 +216,8 @@ key_store_import_key (struct key_store *ks, const struct key_store_key *key)
}
assert (ks != NULL);
- new_keys = realloc (ks->keys, sizeof (*ks->keys) + 1);
+ new_keys = realloc (ks->keys,
+ (ks->nr_keys + 1) * sizeof (struct key_store_key));
if (!new_keys)
error (EXIT_FAILURE, errno, "realloc");
--
2.26.2

View File

@ -1,41 +0,0 @@
From 77604b91ec01ddd7961e69b70727b8e8c6e4c50b Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Fri, 13 Jul 2018 13:24:07 +0200
Subject: [PATCH] v2v: change QXL ResourceType in OVirt flavour (RHBZ#1598715)
Due to a conflict with the IDs of the OVF standard, and the existing
implementation in ovirt-engine, the ID of QXL devices changed to a
different value.
As a consequence, change the ResourceType of QXL devices, but only in
OVirt flavour to avoid breaking vdsm mode.
See: https://bugzilla.redhat.com/show_bug.cgi?id=1598715#c5
(cherry picked from commit aa9e18f6d1fd503822dfd2124b92a2c67704c4c1)
---
v2v/create_ovf.ml | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/v2v/create_ovf.ml b/v2v/create_ovf.ml
index 9e0c772fd..5db239d66 100644
--- a/v2v/create_ovf.ml
+++ b/v2v/create_ovf.ml
@@ -643,10 +643,14 @@ let rec create_ovf source targets guestcaps inspect
* See RHBZ#1213701 and RHBZ#1211231 for the reasoning
* behind that.
*)
+ let qxl_resourcetype =
+ match ovf_flavour with
+ | OVirt -> 32768 (* RHBZ#1598715 *)
+ | RHVExportStorageDomain -> 20 in
e "Item" [] [
e "rasd:Caption" [] [PCData "Graphical Controller"];
e "rasd:InstanceId" [] [PCData (uuidgen ())];
- e "rasd:ResourceType" [] [PCData "20"];
+ e "rasd:ResourceType" [] [PCData (string_of_int qxl_resourcetype)];
e "Type" [] [PCData "video"];
e "rasd:VirtualQuantity" [] [PCData "1"];
e "rasd:Device" [] [PCData "qxl"];
--
2.21.0

View File

@ -0,0 +1,85 @@
From d2ca3f2f9bd9f26cacef2cf2a38e8ac18484d8e4 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 26 Nov 2019 12:12:45 +0000
Subject: [PATCH] options: Simplify selector parsing for --key options.
Refactor this code to use guestfs_int_split_string function which
slightly simplifies it. This should have no effect.
(cherry picked from commit 530d0beef74d48617717463a5b585f21e2ed62be
in libguestfs-common)
---
common/options/keys.c | 35 ++++++++++++++---------------------
1 file changed, 14 insertions(+), 21 deletions(-)
diff --git a/common/options/keys.c b/common/options/keys.c
index f783066ff..74b549731 100644
--- a/common/options/keys.c
+++ b/common/options/keys.c
@@ -153,49 +153,42 @@ get_key (struct key_store *ks, const char *device)
}
struct key_store *
-key_store_add_from_selector (struct key_store *ks, const char *selector_orig)
+key_store_add_from_selector (struct key_store *ks, const char *selector)
{
- CLEANUP_FREE char *selector = strdup (selector_orig);
- const char *elem;
- char *saveptr;
+ CLEANUP_FREE_STRING_LIST char **fields =
+ guestfs_int_split_string (':', selector);
struct key_store_key key;
- if (!selector)
- error (EXIT_FAILURE, errno, "strdup");
+ if (!fields)
+ error (EXIT_FAILURE, errno, "guestfs_int_split_string");
- /* 1: device */
- elem = strtok_r (selector, ":", &saveptr);
- if (!elem) {
+ if (guestfs_int_count_strings (fields) != 3) {
invalid_selector:
- error (EXIT_FAILURE, 0, "invalid selector for --key: %s", selector_orig);
+ error (EXIT_FAILURE, 0, "invalid selector for --key: %s", selector);
}
- key.device = strdup (elem);
+
+ /* 1: device */
+ key.device = strdup (fields[0]);
if (!key.device)
error (EXIT_FAILURE, errno, "strdup");
/* 2: key type */
- elem = strtok_r (NULL, ":", &saveptr);
- if (!elem)
- goto invalid_selector;
- else if (STREQ (elem, "key"))
+ if (STREQ (fields[1], "key"))
key.type = key_string;
- else if (STREQ (elem, "file"))
+ else if (STREQ (fields[1], "file"))
key.type = key_file;
else
goto invalid_selector;
/* 3: actual key */
- elem = strtok_r (NULL, ":", &saveptr);
- if (!elem)
- goto invalid_selector;
switch (key.type) {
case key_string:
- key.string.s = strdup (elem);
+ key.string.s = strdup (fields[2]);
if (!key.string.s)
error (EXIT_FAILURE, errno, "strdup");
break;
case key_file:
- key.file.name = strdup (elem);
+ key.file.name = strdup (fields[2]);
if (!key.file.name)
error (EXIT_FAILURE, errno, "strdup");
break;
--
2.26.2

View File

@ -1,40 +0,0 @@
From bb6b81861e72535f57bdc8e9a3457807f21ad28c Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Tue, 17 Jul 2018 17:12:38 +0200
Subject: [PATCH] v2v: -o rhv-upload: check for ovirtsdk4 (RHBZ#1601943)
Check earlier whether the ovirtsdk4 Python can be imported correctly,
to avoid errors later on during the migration.
---
v2v/output_rhv_upload.ml | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml
index 0152b8d5a..63fa2411a 100644
--- a/v2v/output_rhv_upload.ml
+++ b/v2v/output_rhv_upload.ml
@@ -126,6 +126,13 @@ class output_rhv_upload output_alloc output_conn
python3
in
+ (* Check that the 'ovirtsdk4' Python module is available. *)
+ let error_unless_ovirtsdk4_module_available () =
+ let res = run_command [ python3; "-c"; "import ovirtsdk4" ] in
+ if res <> 0 then
+ error (f_"the Python module ovirtsdk4 could not be loaded, is it installed? See previous messages for problems.")
+ in
+
(* Check that nbdkit is available and new enough. *)
let error_unless_nbdkit_working () =
if 0 <> Sys.command "nbdkit --version >/dev/null" then
@@ -231,6 +238,7 @@ object
method precheck () =
error_unless_python_binary_on_path ();
+ error_unless_ovirtsdk4_module_available ();
error_unless_nbdkit_working ();
error_unless_nbdkit_python3_working ();
error_unless_output_alloc_sparse ();
--
2.21.0

View File

@ -0,0 +1,181 @@
From d3c6f71eed46df3f9ec376359433d9c4b9830860 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 12 Nov 2019 17:50:17 +0000
Subject: [PATCH] options: Allow multiple --key parameters.
This allows multiple --key parameters on the command line to match a
single device. For example:
tool --key /dev/sda1:key:trykey1 --key /dev/sda1:key:trykey2
would try "trykey1" and "trykey2" against /dev/sda1.
(cherry picked from commit c10c8baedb88e7c2988a01b70fc5f81fa8e4885c
in libguestfs-common)
---
common/options/decrypt.c | 37 +++++++++++++++++++++++++--------
common/options/keys.c | 45 +++++++++++++++++++++++++++++++---------
common/options/options.h | 6 ++++--
3 files changed, 67 insertions(+), 21 deletions(-)
diff --git a/common/options/decrypt.c b/common/options/decrypt.c
index 234163d8c..3511d9fe9 100644
--- a/common/options/decrypt.c
+++ b/common/options/decrypt.c
@@ -26,6 +26,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <libintl.h>
+#include <error.h>
+#include <assert.h>
#include "c-ctype.h"
@@ -74,21 +77,37 @@ inspect_do_decrypt (guestfs_h *g, struct key_store *ks)
if (partitions == NULL)
exit (EXIT_FAILURE);
- int need_rescan = 0;
- size_t i;
+ int need_rescan = 0, r;
+ size_t i, j;
+
for (i = 0; partitions[i] != NULL; ++i) {
CLEANUP_FREE char *type = guestfs_vfs_type (g, partitions[i]);
if (type && STREQ (type, "crypto_LUKS")) {
char mapname[32];
make_mapname (partitions[i], mapname, sizeof mapname);
- CLEANUP_FREE char *key = get_key (ks, partitions[i]);
- /* XXX Should we call guestfs_luks_open_ro if readonly flag
- * is set? This might break 'mount_ro'.
- */
- if (guestfs_luks_open (g, partitions[i], key, mapname) == -1)
- exit (EXIT_FAILURE);
-
+ CLEANUP_FREE_STRING_LIST char **keys = get_keys (ks, partitions[i]);
+ assert (guestfs_int_count_strings (keys) > 0);
+
+ /* Try each key in turn. */
+ for (j = 0; keys[j] != NULL; ++j) {
+ /* XXX Should we call guestfs_luks_open_ro if readonly flag
+ * is set? This might break 'mount_ro'.
+ */
+ guestfs_push_error_handler (g, NULL, NULL);
+ r = guestfs_luks_open (g, partitions[i], keys[j], mapname);
+ guestfs_pop_error_handler (g);
+ if (r == 0)
+ goto opened;
+ }
+ error (EXIT_FAILURE, 0,
+ _("could not find key to open LUKS encrypted %s.\n\n"
+ "Try using --key on the command line.\n\n"
+ "Original error: %s (%d)"),
+ partitions[i], guestfs_last_error (g),
+ guestfs_last_errno (g));
+
+ opened:
need_rescan = 1;
}
}
diff --git a/common/options/keys.c b/common/options/keys.c
index 74b549731..782bdb67f 100644
--- a/common/options/keys.c
+++ b/common/options/keys.c
@@ -121,15 +121,32 @@ read_first_line_from_file (const char *filename)
return ret;
}
-char *
-get_key (struct key_store *ks, const char *device)
+/* Return the key(s) matching this particular device from the
+ * keystore. There may be multiple. If none are read from the
+ * keystore, ask the user.
+ */
+char **
+get_keys (struct key_store *ks, const char *device)
{
- size_t i;
+ size_t i, j, len;
+ char **r;
+ char *s;
+
+ /* We know the returned list must have at least one element and not
+ * more than ks->nr_keys.
+ */
+ len = 1;
+ if (ks)
+ len = MIN (1, ks->nr_keys);
+ r = calloc (len+1, sizeof (char *));
+ if (r == NULL)
+ error (EXIT_FAILURE, errno, "calloc");
+
+ j = 0;
if (ks) {
for (i = 0; i < ks->nr_keys; ++i) {
struct key_store_key *key = &ks->keys[i];
- char *s;
if (STRNEQ (key->device, device))
continue;
@@ -139,17 +156,25 @@ get_key (struct key_store *ks, const char *device)
s = strdup (key->string.s);
if (!s)
error (EXIT_FAILURE, errno, "strdup");
- return s;
+ r[j++] = s;
+ break;
case key_file:
- return read_first_line_from_file (key->file.name);
+ s = read_first_line_from_file (key->file.name);
+ r[j++] = s;
+ break;
}
-
- /* Key not found in the key store, ask the user for it. */
- break;
}
}
- return read_key (device);
+ if (j == 0) {
+ /* Key not found in the key store, ask the user for it. */
+ s = read_key (device);
+ if (!s)
+ error (EXIT_FAILURE, 0, _("could not read key from user"));
+ r[0] = s;
+ }
+
+ return r;
}
struct key_store *
diff --git a/common/options/options.h b/common/options/options.h
index 6fadf1e76..510e8a8a9 100644
--- a/common/options/options.h
+++ b/common/options/options.h
@@ -104,7 +104,9 @@ struct mp {
/* A key in the key store. */
struct key_store_key {
- /* The device this key refers to. */
+ /* The device this key refers to. There may be multiple matching
+ * devices in the list.
+ */
char *device;
enum {
@@ -146,7 +148,7 @@ extern void print_inspect_prompt (void);
/* in key.c */
extern char *read_key (const char *param);
-extern char *get_key (struct key_store *ks, const char *device);
+extern char **get_keys (struct key_store *ks, const char *device);
extern struct key_store *key_store_add_from_selector (struct key_store *ks, const char *selector);
extern struct key_store *key_store_import_key (struct key_store *ks, const struct key_store_key *key);
extern void free_key_store (struct key_store *ks);
--
2.26.2

View File

@ -1,29 +0,0 @@
From c0f9ab66655ec5ca3f065357d6797d0061f04fe0 Mon Sep 17 00:00:00 2001
From: Daniel Erez <derez@redhat.com>
Date: Tue, 24 Jul 2018 19:16:10 +0300
Subject: [PATCH] v2v: rhv plugin - fix DC search string
Search for DC by 'storage.name=' to make it explicit.
I.e. "storage=" uses regex, so similar names can be
found in the search query. For example, searching for
a domain named FCSD, will find FCSD1 as well.
---
v2v/rhv-upload-plugin.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index 931fcfaa2..8274f1ee1 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -72,7 +72,7 @@ def find_host(connection):
system_service = connection.system_service()
storage_name = params['output_storage']
data_centers = system_service.data_centers_service().list(
- search='storage=%s' % storage_name,
+ search='storage.name=%s' % storage_name,
case_sensitive=False,
)
if len(data_centers) == 0:
--
2.21.0

View File

@ -0,0 +1,437 @@
From 3afce3e84c79d7fbca4d6eeb76f237090c5528c9 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Fri, 29 Nov 2019 12:06:20 +0100
Subject: [PATCH] options: rename key.device as key.id
In the future it will be also something else other than the device name.
(cherry picked from commit c863ee5e1df5e1eca7ad6821bd2db3796277a6bd
in libguestfs-common)
PT: the documentation was amended manually.
---
cat/virt-cat.pod | 7 ++++---
cat/virt-log.pod | 7 ++++---
cat/virt-ls.pod | 7 ++++---
cat/virt-tail.pod | 7 ++++---
common/mltools/tools_utils-c.c | 4 ++--
common/options/keys.c | 8 ++++----
common/options/options.h | 8 +++++---
customize/virt-customize.pod | 7 ++++---
diff/virt-diff.pod | 7 ++++---
edit/virt-edit.pod | 7 ++++---
fish/guestfish.pod | 7 ++++---
fuse/guestmount.pod | 7 ++++---
get-kernel/virt-get-kernel.pod | 7 ++++---
inspector/virt-inspector.pod | 7 ++++---
sparsify/virt-sparsify.pod | 7 ++++---
sysprep/virt-sysprep.pod | 7 ++++---
v2v/virt-v2v.pod | 7 ++++---
17 files changed, 67 insertions(+), 51 deletions(-)
diff --git a/cat/virt-cat.pod b/cat/virt-cat.pod
index 745d4a4b6..b0301d636 100644
--- a/cat/virt-cat.pod
+++ b/cat/virt-cat.pod
@@ -124,15 +124,16 @@ security problem with malicious guests (CVE-2010-3851).
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<SELECTOR> can be in one of the following formats:
+the inspection. C<ID> must be the libguestfs device name of the LUKS
+device.
=over 4
-=item B<--key> C<DEVICE>:key:KEY_STRING
+=item B<--key> C<ID>:key:KEY_STRING
Use the specified C<KEY_STRING> as passphrase.
-=item B<--key> C<DEVICE>:file:FILENAME
+=item B<--key> C<ID>:file:FILENAME
Read the passphrase from F<FILENAME>.
diff --git a/cat/virt-log.pod b/cat/virt-log.pod
index 8de000c5f..0d447b3b5 100644
--- a/cat/virt-log.pod
+++ b/cat/virt-log.pod
@@ -108,15 +108,16 @@ security problem with malicious guests (CVE-2010-3851).
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<SELECTOR> can be in one of the following formats:
+the inspection. C<ID> must be the libguestfs device name of the LUKS
+device.
=over 4
-=item B<--key> C<DEVICE>:key:KEY_STRING
+=item B<--key> C<ID>:key:KEY_STRING
Use the specified C<KEY_STRING> as passphrase.
-=item B<--key> C<DEVICE>:file:FILENAME
+=item B<--key> C<ID>:file:FILENAME
Read the passphrase from F<FILENAME>.
diff --git a/cat/virt-ls.pod b/cat/virt-ls.pod
index 8d6a9fe37..de02a473d 100644
--- a/cat/virt-ls.pod
+++ b/cat/virt-ls.pod
@@ -355,15 +355,16 @@ L</RECURSIVE LONG LISTING> above.
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<SELECTOR> can be in one of the following formats:
+the inspection. C<ID> must be the libguestfs device name of the LUKS
+device.
=over 4
-=item B<--key> C<DEVICE>:key:KEY_STRING
+=item B<--key> C<ID>:key:KEY_STRING
Use the specified C<KEY_STRING> as passphrase.
-=item B<--key> C<DEVICE>:file:FILENAME
+=item B<--key> C<ID>:file:FILENAME
Read the passphrase from F<FILENAME>.
diff --git a/cat/virt-tail.pod b/cat/virt-tail.pod
index cf8700d1a..f00384f5d 100644
--- a/cat/virt-tail.pod
+++ b/cat/virt-tail.pod
@@ -126,15 +126,16 @@ security problem with malicious guests (CVE-2010-3851).
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<SELECTOR> can be in one of the following formats:
+the inspection. C<ID> must be the libguestfs device name of the LUKS
+device.
=over 4
-=item B<--key> C<DEVICE>:key:KEY_STRING
+=item B<--key> C<ID>:key:KEY_STRING
Use the specified C<KEY_STRING> as passphrase.
-=item B<--key> C<DEVICE>:file:FILENAME
+=item B<--key> C<ID>:file:FILENAME
Read the passphrase from F<FILENAME>.
diff --git a/common/mltools/tools_utils-c.c b/common/mltools/tools_utils-c.c
index 3b80091c0..6c43b8d74 100644
--- a/common/mltools/tools_utils-c.c
+++ b/common/mltools/tools_utils-c.c
@@ -57,8 +57,8 @@ guestfs_int_mllib_inspect_decrypt (value gv, value gpv, value keysv)
struct key_store_key key;
elemv = Field (keysv, 0);
- key.device = strdup (String_val (Field (elemv, 0)));
- if (!key.device)
+ key.id = strdup (String_val (Field (elemv, 0)));
+ if (!key.id)
caml_raise_out_of_memory ();
v = Field (elemv, 1);
diff --git a/common/options/keys.c b/common/options/keys.c
index 782bdb67f..7c391acde 100644
--- a/common/options/keys.c
+++ b/common/options/keys.c
@@ -148,7 +148,7 @@ get_keys (struct key_store *ks, const char *device)
for (i = 0; i < ks->nr_keys; ++i) {
struct key_store_key *key = &ks->keys[i];
- if (STRNEQ (key->device, device))
+ if (STRNEQ (key->id, device))
continue;
switch (key->type) {
@@ -193,8 +193,8 @@ key_store_add_from_selector (struct key_store *ks, const char *selector)
}
/* 1: device */
- key.device = strdup (fields[0]);
- if (!key.device)
+ key.id = strdup (fields[0]);
+ if (!key.id)
error (EXIT_FAILURE, errno, "strdup");
/* 2: key type */
@@ -265,6 +265,6 @@ free_key_store (struct key_store *ks)
free (key->file.name);
break;
}
- free (key->device);
+ free (key->id);
}
}
diff --git a/common/options/options.h b/common/options/options.h
index 510e8a8a9..b83a92b06 100644
--- a/common/options/options.h
+++ b/common/options/options.h
@@ -104,10 +104,12 @@ struct mp {
/* A key in the key store. */
struct key_store_key {
- /* The device this key refers to. There may be multiple matching
- * devices in the list.
+ /* An ID for the device this key refers to. It must be the libguestfs
+ * device name.
+ *
+ * There may be multiple matching devices in the list.
*/
- char *device;
+ char *id;
enum {
key_string, /* key specified as string */
diff --git a/customize/virt-customize.pod b/customize/virt-customize.pod
index d1b568040..491606591 100644
--- a/customize/virt-customize.pod
+++ b/customize/virt-customize.pod
@@ -141,15 +141,16 @@ security problem with malicious guests (CVE-2010-3851).
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<SELECTOR> can be in one of the following formats:
+the inspection. C<ID> must be the libguestfs device name of the LUKS
+device.
=over 4
-=item B<--key> C<DEVICE>:key:KEY_STRING
+=item B<--key> C<ID>:key:KEY_STRING
Use the specified C<KEY_STRING> as passphrase.
-=item B<--key> C<DEVICE>:file:FILENAME
+=item B<--key> C<ID>:file:FILENAME
Read the passphrase from F<FILENAME>.
diff --git a/diff/virt-diff.pod b/diff/virt-diff.pod
index 36ee10ced..22658072d 100644
--- a/diff/virt-diff.pod
+++ b/diff/virt-diff.pod
@@ -169,15 +169,16 @@ Display file sizes in human-readable format.
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<SELECTOR> can be in one of the following formats:
+the inspection. C<ID> must be the libguestfs device name of the LUKS
+device.
=over 4
-=item B<--key> C<DEVICE>:key:KEY_STRING
+=item B<--key> C<ID>:key:KEY_STRING
Use the specified C<KEY_STRING> as passphrase.
-=item B<--key> C<DEVICE>:file:FILENAME
+=item B<--key> C<ID>:file:FILENAME
Read the passphrase from F<FILENAME>.
diff --git a/edit/virt-edit.pod b/edit/virt-edit.pod
index 3cb3ce6da..5a63cd05f 100644
--- a/edit/virt-edit.pod
+++ b/edit/virt-edit.pod
@@ -156,15 +156,16 @@ security problem with malicious guests (CVE-2010-3851).
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<SELECTOR> can be in one of the following formats:
+the inspection. C<ID> must be the libguestfs device name of the LUKS
+device.
=over 4
-=item B<--key> C<DEVICE>:key:KEY_STRING
+=item B<--key> C<ID>:key:KEY_STRING
Use the specified C<KEY_STRING> as passphrase.
-=item B<--key> C<DEVICE>:file:FILENAME
+=item B<--key> C<ID>:file:FILENAME
Read the passphrase from F<FILENAME>.
diff --git a/fish/guestfish.pod b/fish/guestfish.pod
index 06644c5b8..ccb57b159 100644
--- a/fish/guestfish.pod
+++ b/fish/guestfish.pod
@@ -283,15 +283,16 @@ were found.
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<SELECTOR> can be in one of the following formats:
+the inspection. C<ID> must be the libguestfs device name of the LUKS
+device.
=over 4
-=item B<--key> C<DEVICE>:key:KEY_STRING
+=item B<--key> C<ID>:key:KEY_STRING
Use the specified C<KEY_STRING> as passphrase.
-=item B<--key> C<DEVICE>:file:FILENAME
+=item B<--key> C<ID>:file:FILENAME
Read the passphrase from F<FILENAME>.
diff --git a/fuse/guestmount.pod b/fuse/guestmount.pod
index 9319d093c..d9e957b8b 100644
--- a/fuse/guestmount.pod
+++ b/fuse/guestmount.pod
@@ -249,15 +249,16 @@ mounted on the real virtual machine.
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<SELECTOR> can be in one of the following formats:
+the inspection. C<ID> must be the libguestfs device name of the LUKS
+device.
=over 4
-=item B<--key> C<DEVICE>:key:KEY_STRING
+=item B<--key> C<ID>:key:KEY_STRING
Use the specified C<KEY_STRING> as passphrase.
-=item B<--key> C<DEVICE>:file:FILENAME
+=item B<--key> C<ID>:file:FILENAME
Read the passphrase from F<FILENAME>.
diff --git a/get-kernel/virt-get-kernel.pod b/get-kernel/virt-get-kernel.pod
index 3802412e2..f0ace2d6d 100644
--- a/get-kernel/virt-get-kernel.pod
+++ b/get-kernel/virt-get-kernel.pod
@@ -92,15 +92,16 @@ security problem with malicious guests (CVE-2010-3851).
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<SELECTOR> can be in one of the following formats:
+the inspection. C<ID> must be the libguestfs device name of the LUKS
+device.
=over 4
-=item B<--key> C<DEVICE>:key:KEY_STRING
+=item B<--key> C<ID>:key:KEY_STRING
Use the specified C<KEY_STRING> as passphrase.
-=item B<--key> C<DEVICE>:file:FILENAME
+=item B<--key> C<ID>:file:FILENAME
Read the passphrase from F<FILENAME>.
diff --git a/inspector/virt-inspector.pod b/inspector/virt-inspector.pod
index 98b278f26..eac9dc3cd 100644
--- a/inspector/virt-inspector.pod
+++ b/inspector/virt-inspector.pod
@@ -117,15 +117,16 @@ ensure the format is always specified.
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<SELECTOR> can be in one of the following formats:
+the inspection. C<ID> must be the libguestfs device name of the LUKS
+device.
=over 4
-=item B<--key> C<DEVICE>:key:KEY_STRING
+=item B<--key> C<ID>:key:KEY_STRING
Use the specified C<KEY_STRING> as passphrase.
-=item B<--key> C<DEVICE>:file:FILENAME
+=item B<--key> C<ID>:file:FILENAME
Read the passphrase from F<FILENAME>.
diff --git a/sparsify/virt-sparsify.pod b/sparsify/virt-sparsify.pod
index 3f5f9995f..cf7970a5f 100644
--- a/sparsify/virt-sparsify.pod
+++ b/sparsify/virt-sparsify.pod
@@ -233,15 +233,16 @@ See L</IN-PLACE SPARSIFICATION> below.
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<SELECTOR> can be in one of the following formats:
+the inspection. C<ID> must be the libguestfs device name of the LUKS
+device.
=over 4
-=item B<--key> C<DEVICE>:key:KEY_STRING
+=item B<--key> C<ID>:key:KEY_STRING
Use the specified C<KEY_STRING> as passphrase.
-=item B<--key> C<DEVICE>:file:FILENAME
+=item B<--key> C<ID>:file:FILENAME
Read the passphrase from F<FILENAME>.
diff --git a/sysprep/virt-sysprep.pod b/sysprep/virt-sysprep.pod
index 8d248db94..d7ad7ee33 100644
--- a/sysprep/virt-sysprep.pod
+++ b/sysprep/virt-sysprep.pod
@@ -189,15 +189,16 @@ security problem with malicious guests (CVE-2010-3851).
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<SELECTOR> can be in one of the following formats:
+the inspection. C<ID> must be the libguestfs device name of the LUKS
+device.
=over 4
-=item B<--key> C<DEVICE>:key:KEY_STRING
+=item B<--key> C<ID>:key:KEY_STRING
Use the specified C<KEY_STRING> as passphrase.
-=item B<--key> C<DEVICE>:file:FILENAME
+=item B<--key> C<ID>:file:FILENAME
Read the passphrase from F<FILENAME>.
diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
index 0642d158f..8c2867814 100644
--- a/v2v/virt-v2v.pod
+++ b/v2v/virt-v2v.pod
@@ -337,15 +337,16 @@ through VDDK.
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<SELECTOR> can be in one of the following formats:
+the inspection. C<ID> must be the libguestfs device name of the LUKS
+device.
=over 4
-=item B<--key> C<DEVICE>:key:KEY_STRING
+=item B<--key> C<ID>:key:KEY_STRING
Use the specified C<KEY_STRING> as passphrase.
-=item B<--key> C<DEVICE>:file:FILENAME
+=item B<--key> C<ID>:file:FILENAME
Read the passphrase from F<FILENAME>.
--
2.26.2

View File

@ -1,35 +0,0 @@
From bc2ba2f47ba8a1f88ea6f3c14addd60e84423adf Mon Sep 17 00:00:00 2001
From: Daniel Erez <derez@redhat.com>
Date: Wed, 25 Jul 2018 11:24:33 +0300
Subject: [PATCH] v2v: rhv plugin - case-sensitive search queries
Changed both search queries to case-sensitive (to ensure an exact match).
---
v2v/rhv-upload-plugin.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index 8274f1ee1..4fad27fb8 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -73,7 +73,7 @@ def find_host(connection):
storage_name = params['output_storage']
data_centers = system_service.data_centers_service().list(
search='storage.name=%s' % storage_name,
- case_sensitive=False,
+ case_sensitive=True,
)
if len(data_centers) == 0:
# The storage domain is not attached to a datacenter
@@ -87,7 +87,7 @@ def find_host(connection):
hosts_service = system_service.hosts_service()
hosts = hosts_service.list(
search="hw_id=%s and datacenter=%s and status=Up" % (vdsm_id, datacenter.name),
- case_sensitive=False,
+ case_sensitive=True,
)
if len(hosts) == 0:
# Couldn't find a host that's fulfilling the following criteria:
--
2.21.0

View File

@ -0,0 +1,313 @@
From abb0a1dcc6e15130c334713d0716e223e5fc494d Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Fri, 29 Nov 2019 12:07:13 +0100
Subject: [PATCH] options: allow a UUID as identifier for --key
This way it is possible to specify the UUID of the LUKS device instead
of the libguestfs device name to decrypt a device during the inspection.
Make the usage of the new luks_uuid API conditional, so other projects
using the common submodule do not require a libguestfs version bump.
(cherry picked from commit bb4a2dc17a78b53437896d4215ae82df8e11b788
in libguestfs-common)
PT: the documentation was amended manually.
---
cat/virt-cat.pod | 4 ++--
cat/virt-log.pod | 4 ++--
cat/virt-ls.pod | 4 ++--
cat/virt-tail.pod | 4 ++--
common/options/decrypt.c | 8 +++++++-
common/options/keys.c | 4 ++--
common/options/options.h | 6 +++---
customize/virt-customize.pod | 4 ++--
diff/virt-diff.pod | 4 ++--
edit/virt-edit.pod | 4 ++--
fish/guestfish.pod | 4 ++--
fuse/guestmount.pod | 4 ++--
get-kernel/virt-get-kernel.pod | 4 ++--
inspector/virt-inspector.pod | 4 ++--
sparsify/virt-sparsify.pod | 4 ++--
sysprep/virt-sysprep.pod | 4 ++--
v2v/virt-v2v.pod | 4 ++--
17 files changed, 40 insertions(+), 34 deletions(-)
diff --git a/cat/virt-cat.pod b/cat/virt-cat.pod
index b0301d636..2cea291ac 100644
--- a/cat/virt-cat.pod
+++ b/cat/virt-cat.pod
@@ -124,8 +124,8 @@ security problem with malicious guests (CVE-2010-3851).
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<ID> must be the libguestfs device name of the LUKS
-device.
+the inspection. C<ID> can be either the libguestfs device name, or
+the UUID of the LUKS device.
=over 4
diff --git a/cat/virt-log.pod b/cat/virt-log.pod
index 0d447b3b5..888108d5f 100644
--- a/cat/virt-log.pod
+++ b/cat/virt-log.pod
@@ -108,8 +108,8 @@ security problem with malicious guests (CVE-2010-3851).
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<ID> must be the libguestfs device name of the LUKS
-device.
+the inspection. C<ID> can be either the libguestfs device name, or
+the UUID of the LUKS device.
=over 4
diff --git a/cat/virt-ls.pod b/cat/virt-ls.pod
index de02a473d..307e79395 100644
--- a/cat/virt-ls.pod
+++ b/cat/virt-ls.pod
@@ -355,8 +355,8 @@ L</RECURSIVE LONG LISTING> above.
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<ID> must be the libguestfs device name of the LUKS
-device.
+the inspection. C<ID> can be either the libguestfs device name, or
+the UUID of the LUKS device.
=over 4
diff --git a/cat/virt-tail.pod b/cat/virt-tail.pod
index f00384f5d..a804f4cf3 100644
--- a/cat/virt-tail.pod
+++ b/cat/virt-tail.pod
@@ -126,8 +126,8 @@ security problem with malicious guests (CVE-2010-3851).
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<ID> must be the libguestfs device name of the LUKS
-device.
+the inspection. C<ID> can be either the libguestfs device name, or
+the UUID of the LUKS device.
=over 4
diff --git a/common/options/decrypt.c b/common/options/decrypt.c
index 3511d9fe9..683cf5ed4 100644
--- a/common/options/decrypt.c
+++ b/common/options/decrypt.c
@@ -86,7 +86,13 @@ inspect_do_decrypt (guestfs_h *g, struct key_store *ks)
char mapname[32];
make_mapname (partitions[i], mapname, sizeof mapname);
- CLEANUP_FREE_STRING_LIST char **keys = get_keys (ks, partitions[i]);
+#ifdef GUESTFS_HAVE_LUKS_UUID
+ CLEANUP_FREE char *uuid = guestfs_luks_uuid (g, partitions[i]);
+#else
+ const char *uuid = NULL;
+#endif
+
+ CLEANUP_FREE_STRING_LIST char **keys = get_keys (ks, partitions[i], uuid);
assert (guestfs_int_count_strings (keys) > 0);
/* Try each key in turn. */
diff --git a/common/options/keys.c b/common/options/keys.c
index 7c391acde..798315c2e 100644
--- a/common/options/keys.c
+++ b/common/options/keys.c
@@ -126,7 +126,7 @@ read_first_line_from_file (const char *filename)
* keystore, ask the user.
*/
char **
-get_keys (struct key_store *ks, const char *device)
+get_keys (struct key_store *ks, const char *device, const char *uuid)
{
size_t i, j, len;
char **r;
@@ -148,7 +148,7 @@ get_keys (struct key_store *ks, const char *device)
for (i = 0; i < ks->nr_keys; ++i) {
struct key_store_key *key = &ks->keys[i];
- if (STRNEQ (key->id, device))
+ if (STRNEQ (key->id, device) && (uuid && STRNEQ (key->id, uuid)))
continue;
switch (key->type) {
diff --git a/common/options/options.h b/common/options/options.h
index b83a92b06..9b7830220 100644
--- a/common/options/options.h
+++ b/common/options/options.h
@@ -104,8 +104,8 @@ struct mp {
/* A key in the key store. */
struct key_store_key {
- /* An ID for the device this key refers to. It must be the libguestfs
- * device name.
+ /* An ID for the device this key refers to. It can be either the libguestfs
+ * device name, or the UUID.
*
* There may be multiple matching devices in the list.
*/
@@ -150,7 +150,7 @@ extern void print_inspect_prompt (void);
/* in key.c */
extern char *read_key (const char *param);
-extern char **get_keys (struct key_store *ks, const char *device);
+extern char **get_keys (struct key_store *ks, const char *device, const char *uuid);
extern struct key_store *key_store_add_from_selector (struct key_store *ks, const char *selector);
extern struct key_store *key_store_import_key (struct key_store *ks, const struct key_store_key *key);
extern void free_key_store (struct key_store *ks);
diff --git a/customize/virt-customize.pod b/customize/virt-customize.pod
index 491606591..5d92486a2 100644
--- a/customize/virt-customize.pod
+++ b/customize/virt-customize.pod
@@ -141,8 +141,8 @@ security problem with malicious guests (CVE-2010-3851).
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<ID> must be the libguestfs device name of the LUKS
-device.
+the inspection. C<ID> can be either the libguestfs device name, or
+the UUID of the LUKS device.
=over 4
diff --git a/diff/virt-diff.pod b/diff/virt-diff.pod
index 22658072d..e67d09101 100644
--- a/diff/virt-diff.pod
+++ b/diff/virt-diff.pod
@@ -169,8 +169,8 @@ Display file sizes in human-readable format.
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<ID> must be the libguestfs device name of the LUKS
-device.
+the inspection. C<ID> can be either the libguestfs device name, or
+the UUID of the LUKS device.
=over 4
diff --git a/edit/virt-edit.pod b/edit/virt-edit.pod
index 5a63cd05f..918fa66f2 100644
--- a/edit/virt-edit.pod
+++ b/edit/virt-edit.pod
@@ -156,8 +156,8 @@ security problem with malicious guests (CVE-2010-3851).
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<ID> must be the libguestfs device name of the LUKS
-device.
+the inspection. C<ID> can be either the libguestfs device name, or
+the UUID of the LUKS device.
=over 4
diff --git a/fish/guestfish.pod b/fish/guestfish.pod
index ccb57b159..f1fdf094d 100644
--- a/fish/guestfish.pod
+++ b/fish/guestfish.pod
@@ -283,8 +283,8 @@ were found.
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<ID> must be the libguestfs device name of the LUKS
-device.
+the inspection. C<ID> can be either the libguestfs device name, or
+the UUID of the LUKS device.
=over 4
diff --git a/fuse/guestmount.pod b/fuse/guestmount.pod
index d9e957b8b..3a02c087c 100644
--- a/fuse/guestmount.pod
+++ b/fuse/guestmount.pod
@@ -249,8 +249,8 @@ mounted on the real virtual machine.
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<ID> must be the libguestfs device name of the LUKS
-device.
+the inspection. C<ID> can be either the libguestfs device name, or
+the UUID of the LUKS device.
=over 4
diff --git a/get-kernel/virt-get-kernel.pod b/get-kernel/virt-get-kernel.pod
index f0ace2d6d..78fe66df4 100644
--- a/get-kernel/virt-get-kernel.pod
+++ b/get-kernel/virt-get-kernel.pod
@@ -92,8 +92,8 @@ security problem with malicious guests (CVE-2010-3851).
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<ID> must be the libguestfs device name of the LUKS
-device.
+the inspection. C<ID> can be either the libguestfs device name, or
+the UUID of the LUKS device.
=over 4
diff --git a/inspector/virt-inspector.pod b/inspector/virt-inspector.pod
index eac9dc3cd..625da876c 100644
--- a/inspector/virt-inspector.pod
+++ b/inspector/virt-inspector.pod
@@ -117,8 +117,8 @@ ensure the format is always specified.
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<ID> must be the libguestfs device name of the LUKS
-device.
+the inspection. C<ID> can be either the libguestfs device name, or
+the UUID of the LUKS device.
=over 4
diff --git a/sparsify/virt-sparsify.pod b/sparsify/virt-sparsify.pod
index cf7970a5f..0767d07e6 100644
--- a/sparsify/virt-sparsify.pod
+++ b/sparsify/virt-sparsify.pod
@@ -233,8 +233,8 @@ See L</IN-PLACE SPARSIFICATION> below.
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<ID> must be the libguestfs device name of the LUKS
-device.
+the inspection. C<ID> can be either the libguestfs device name, or
+the UUID of the LUKS device.
=over 4
diff --git a/sysprep/virt-sysprep.pod b/sysprep/virt-sysprep.pod
index d7ad7ee33..b38c76c70 100644
--- a/sysprep/virt-sysprep.pod
+++ b/sysprep/virt-sysprep.pod
@@ -189,8 +189,8 @@ security problem with malicious guests (CVE-2010-3851).
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<ID> must be the libguestfs device name of the LUKS
-device.
+the inspection. C<ID> can be either the libguestfs device name, or
+the UUID of the LUKS device.
=over 4
diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
index 8c2867814..25041d0ec 100644
--- a/v2v/virt-v2v.pod
+++ b/v2v/virt-v2v.pod
@@ -337,8 +337,8 @@ through VDDK.
=item B<--key> SELECTOR
Specify a key for LUKS, to automatically open a LUKS device when using
-the inspection. C<ID> must be the libguestfs device name of the LUKS
-device.
+the inspection. C<ID> can be either the libguestfs device name, or
+the UUID of the LUKS device.
=over 4
--
2.26.2

View File

@ -1,44 +0,0 @@
From 21cf4aaafb6088168d2f5c679477644c19116f3d Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Fri, 20 Apr 2018 15:27:04 +0200
Subject: [PATCH] uefi: remove last references to kraxel's old edk2 builds
Commit 889386f8c6088e57fd68f2bb6bf85f69ecfc6f6c removed most of them
already, so remove the last ones, and the supporting code.
---
generator/UEFI.ml | 6 ------
v2v/utils.ml | 1 -
2 files changed, 7 deletions(-)
diff --git a/generator/UEFI.ml b/generator/UEFI.ml
index daa78bdc9..bca3fa1ae 100644
--- a/generator/UEFI.ml
+++ b/generator/UEFI.ml
@@ -30,12 +30,6 @@ open Docstrings
(* Order is significant *within architectures only*. *)
let firmware = [
- "i386",
- "/usr/share/edk2.git/ovmf-ia32/OVMF_CODE-pure-efi.fd",
- None,
- "/usr/share/edk2.git/ovmf-ia32/OVMF_VARS-pure-efi.fd",
- [];
-
"x86_64",
"/usr/share/OVMF/OVMF_CODE.fd",
None,
diff --git a/v2v/utils.ml b/v2v/utils.ml
index e880001eb..67e2028f3 100644
--- a/v2v/utils.ml
+++ b/v2v/utils.ml
@@ -64,7 +64,6 @@ let find_uefi_firmware guest_arch =
let files =
(* The lists of firmware are actually defined in common/utils/uefi.c. *)
match guest_arch with
- | "i386" | "i486" | "i586" | "i686" -> Uefi.uefi_i386_firmware
| "x86_64" -> Uefi.uefi_x86_64_firmware
| "aarch64" -> Uefi.uefi_aarch64_firmware
| arch ->
--
2.21.0

View File

@ -0,0 +1,82 @@
From 34b2da989021994389b6392fca06590424b7c975 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Wed, 18 Dec 2019 12:12:26 +0100
Subject: [PATCH] docs: remove paragraph about VMware tools on Windows
(RHBZ#1785528)
Starting from libguestfs/virt-v2v 1.39.12, virt-v2v attempts to
uninstall the VMware tools from Windows guests, so there is no need to
remove them manually before the conversion.
Thanks to: Ming Xie.
(cherry picked from commit 397b4a90d16f4eb116d55605cbdf3bd844108315
in virt-v2v)
---
v2v/virt-v2v-input-vmware.pod | 36 -----------------------------------
1 file changed, 36 deletions(-)
diff --git a/v2v/virt-v2v-input-vmware.pod b/v2v/virt-v2v-input-vmware.pod
index 3acdd773e..16ddb045f 100644
--- a/v2v/virt-v2v-input-vmware.pod
+++ b/v2v/virt-v2v-input-vmware.pod
@@ -106,18 +106,6 @@ If you find a folder of files called F<I<guest>.vmx>,
F<I<guest>.vmxf>, F<I<guest>.nvram> and one or more F<.vmdk> disk
images, then you can use this method.
-=head2 VMX: Remove VMware tools from Windows guests
-
-For Windows guests, you should remove VMware tools before conversion.
-Although this is not strictly necessary, and the guest will still be
-able to run, if you don't do this then the converted guest will
-complain on every boot. The tools cannot be removed after conversion
-because the uninstaller checks if it is running on VMware and refuses
-to start (which is also the reason that virt-v2v cannot remove them).
-
-This is not necessary for Linux guests, as virt-v2v is able to remove
-VMware tools.
-
=head2 VMX: Guest must be shut down
B<The guest must be shut down before conversion starts>. If you don't
@@ -319,18 +307,6 @@ Virt-v2v is able to import guests from VMwares OVA (Open
Virtualization Appliance) files. Only OVAs exported from VMware
vSphere will work.
-=head2 OVA: Remove VMware tools from Windows guests
-
-For Windows guests, you should remove VMware tools before conversion.
-Although this is not strictly necessary, and the guest will still be
-able to run, if you don't do this then the converted guest will
-complain on every boot. The tools cannot be removed after conversion
-because the uninstaller checks if it is running on VMware and refuses
-to start (which is also the reason that virt-v2v cannot remove them).
-
-This is not necessary for Linux guests, as virt-v2v is able to remove
-VMware tools.
-
=head2 OVA: Create OVA
To create an OVA in vSphere, use the "Export OVF Template" option
@@ -383,18 +359,6 @@ Virt-v2v uses libvirt for access to vCenter, and therefore the input
mode should be I<-i libvirt>. As this is the default, you don't need
to specify it on the command line.
-=head2 vCenter: Remove VMware tools from Windows guests
-
-For Windows guests, you should remove VMware tools before conversion.
-Although this is not strictly necessary, and the guest will still be
-able to run, if you don't do this then the converted guest will
-complain on every boot. The tools cannot be removed after conversion
-because the uninstaller checks if it is running on VMware and refuses
-to start (which is also the reason that virt-v2v cannot remove them).
-
-This is not necessary for Linux guests, as virt-v2v is able to remove
-VMware tools.
-
=head2 vCenter: URI
The libvirt URI of a vCenter server looks something like this:
--
2.26.2

View File

@ -1,38 +0,0 @@
From bb804081e9b5fc959b14d2e254d320cf5a658441 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Thu, 9 Aug 2018 15:01:37 +0200
Subject: [PATCH] v2v: parse_libvirt_xml: handle srN CDROM devices
(RHBZ#1612785)
This device naming is mostly written by virt-p2v, so get the slot from
it directly without using the drive_index "decoding" function.
(cherry picked from commit c9abaa3e96e7209595f0982c1f2f97e37f3369a6)
---
v2v/parse_libvirt_xml.ml | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/v2v/parse_libvirt_xml.ml b/v2v/parse_libvirt_xml.ml
index 03a201e77..44723014c 100644
--- a/v2v/parse_libvirt_xml.ml
+++ b/v2v/parse_libvirt_xml.ml
@@ -379,6 +379,16 @@ let parse_libvirt_xml ?conn xml =
let target_dev = xpath_string "target/@dev" in
match target_dev with
| None -> None
+ | Some dev when String.is_prefix dev "sr" ->
+ (* "srN" devices are found mostly in the physical XML written by
+ * virt-p2v.
+ *)
+ let name = String.sub dev 2 (String.length dev - 2) in
+ (try Some (int_of_string name)
+ with Failure _ ->
+ warning (f_"could not parse device name %s from the source libvirt XML") dev;
+ None
+ )
| Some dev ->
let rec loop = function
| [] ->
--
2.21.0

View File

@ -0,0 +1,29 @@
From 3dc8b808bdc992fb72372ece84b45644bef2c206 Mon Sep 17 00:00:00 2001
From: Martin Kletzander <mkletzan@redhat.com>
Date: Mon, 24 Feb 2020 13:12:03 +0100
Subject: [PATCH] mlcustomize: Trim whitespaces from commands read from file
(RHBZ#1351000)
The first split does not care about the whole string, it is just trying to get
the command name in front, so triml is just right.
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
---
generator/customize.ml | 1 +
1 file changed, 1 insertion(+)
diff --git a/generator/customize.ml b/generator/customize.ml
index c278347c1..0b256e2d2 100644
--- a/generator/customize.ml
+++ b/generator/customize.ml
@@ -873,6 +873,7 @@ let rec argspec () =
pr " ] in
let lines = read_whole_file filename in
let lines = String.lines_split lines in
+ let lines = List.map String.triml lines in
let lines = List.filter (
fun line ->
String.length line > 0 && line.[0] <> '#'
--
2.26.2

View File

@ -1,43 +0,0 @@
From 6f116349a2a02739e64a39ab2aeb23706fac188b Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 14 Aug 2018 12:50:07 +0100
Subject: [PATCH] v2v: -o rhv-upload: Fix error message disk numbering
(RHBZ#1615885).
The output method used the s_disk_id field assuming it was a unique,
monotonically increasing number counting from 0. However this is not
the case, the input method simply has to set s_disk_id to be unique
for each disk.
Fixes commit cc04573927cca97de60d544d37467e67c25867a7.
Thanks: Xiaodai Wang
(cherry picked from commit 90c9c12258fbb9a89d16f798725d16fe5bb3504c)
---
v2v/output_rhv_upload.ml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml
index 63fa2411a..7dbd98a0d 100644
--- a/v2v/output_rhv_upload.ml
+++ b/v2v/output_rhv_upload.ml
@@ -383,13 +383,13 @@ If the messages above are not sufficient to diagnose the problem then add the
*)
let nr_disks = List.length targets in
let image_uuids =
- List.map (
- fun t ->
+ List.mapi (
+ fun i t ->
let id = t.target_overlay.ov_source.s_disk_id in
let diskid_file = diskid_file_of_id id in
if not (wait_for_file diskid_file finalization_timeout) then
error (f_"transfer of disk %d/%d failed, see earlier error messages")
- (id+1) nr_disks;
+ (i+1) nr_disks;
let diskid = read_whole_file diskid_file in
diskid
) targets in
--
2.21.0

View File

@ -0,0 +1,43 @@
From a4433085bf38719bd22a7cfe507c503885c839f2 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 4 Feb 2020 14:39:39 +0000
Subject: [PATCH] openstack: Increase Cinder volume attach timeout to 5 minutes
(RHBZ#1685032).
In some cases we have observed the time taken for a Cinder volume to
attach to the conversion appliance can be longer than the current 60
seconds. Increase the timeout to 5 minutes.
Thanks: Ming Xie.
(cherry picked from commit e2ce290f6e366716f857eeaddc1dc680e5608c80
in virt-v2v)
---
v2v/output_openstack.ml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/v2v/output_openstack.ml b/v2v/output_openstack.ml
index d187f1d5d..bebf9af18 100644
--- a/v2v/output_openstack.ml
+++ b/v2v/output_openstack.ml
@@ -38,7 +38,7 @@ let openstack_binary = "openstack"
let available_timeout = 300 (* seconds *)
(* Timeout waiting for Cinder volumes to attach to the appliance. *)
-let attach_timeout = 60 (* seconds *)
+let attach_timeout = 300 (* seconds *)
(* The -oo options supported by this output method. *)
type os_options = {
@@ -336,7 +336,7 @@ class output_openstack output_conn output_password output_storage
if String.length id > prefix_len then String.sub id 0 prefix_len
else id in
- with_timeout
+ with_timeout ~sleep:5
(sprintf (f_"waiting for cinder volume %s to attach to the conversion appliance") id)
attach_timeout
(fun () ->
--
2.26.2

View File

@ -1,30 +0,0 @@
From 739ac1bc0f37c4bceb2e2eeed00f9320605aa641 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 7 Aug 2018 09:06:46 +0100
Subject: [PATCH] v2v: -o rhv-upload: Properly replace SD_UUID in OVF
(RHBZ#1612653).
The @SD_UUID@ pattern was not being replaced correctly.
Thanks: Daniel Erez.
(cherry picked from commit 389e165519c33b5234db50ea26dcb267321ee152)
---
v2v/rhv-upload-createvm.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/v2v/rhv-upload-createvm.py b/v2v/rhv-upload-createvm.py
index a34627ec8..1d0e8c95d 100644
--- a/v2v/rhv-upload-createvm.py
+++ b/v2v/rhv-upload-createvm.py
@@ -70,7 +70,7 @@ sds_service = system_service.storage_domains_service()
sd = sds_service.list(search=("name=%s" % params['output_storage']))[0]
sd_uuid = sd.id
-ovf.replace("@SD_UUID@", sd_uuid)
+ovf = ovf.replace("@SD_UUID@", sd_uuid)
vms_service = system_service.vms_service()
vm = vms_service.add(
--
2.21.0

View File

@ -1,28 +0,0 @@
From 8be6817e95dbdf826a6065751b4a3a000c78071c Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 28 Aug 2018 12:59:06 +0100
Subject: [PATCH] ppc64le: Don't use -cpu parameter under any circumstances
(RHBZ#1605071).
(cherry picked from commit 56318f0b5ffc287fed71cc7cdd2007dff2b8fb17)
---
lib/appliance-cpu.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lib/appliance-cpu.c b/lib/appliance-cpu.c
index a6c1b0faf..fa1bae3f9 100644
--- a/lib/appliance-cpu.c
+++ b/lib/appliance-cpu.c
@@ -76,6 +76,9 @@ guestfs_int_get_cpu_model (int kvm)
return "host";
else
return "cortex-a57";
+#elif defined(__powerpc64__)
+ /* See discussion in https://bugzilla.redhat.com/show_bug.cgi?id=1605071 */
+ return NULL;
#else
/* On most architectures, it is faster to pass the CPU host model to
* the appliance, allowing maximum speed for things like checksums
--
2.21.0

View File

@ -0,0 +1,35 @@
From d02694e659ebe1ecad29f8461d87eda6a1f8faa2 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Thu, 19 Sep 2019 09:52:41 +0200
Subject: [PATCH] v2v: -o rhv-upload: check for a valid image transfer right
away
Check for the INITIALIZING state of the image transfer right away,
without waiting 5 seconds even before the first time: this way, if the
transfer is already in the right state then there is no need to wait.
---
v2v/rhv-upload-plugin.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index 6ec74a5d4..7f62b4e3b 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -190,13 +190,13 @@ def open(readonly):
# actual transfer can start when its status is "Transferring".
endt = time.time() + timeout
while True:
- time.sleep(5)
transfer = transfer_service.get()
if transfer.phase != types.ImageTransferPhase.INITIALIZING:
break
if time.time() > endt:
raise RuntimeError("timed out waiting for transfer status "
"!= INITIALIZING")
+ time.sleep(5)
# Now we have permission to start the transfer.
if params['rhv_direct']:
--
2.26.2

View File

@ -0,0 +1,49 @@
From 200a365f20d5d8a3ddfe713e9bbe938206e43e9a Mon Sep 17 00:00:00 2001
From: Nir Soffer <nirsof@gmail.com>
Date: Mon, 18 Nov 2019 01:04:24 +0200
Subject: [PATCH] rhv-upload: Check status more frequently
Checking status more frequently save a couple of seconds. Here is
an example flow tested with oVirt upload_disk.py example:
With 5 seconds wait:
Created disk in 11.085111 seconds
Created transfer in 1.857502 seconds
With 1 second wait:
Created disk in 4.991227 seconds
Created transfer in 1.961243 seconds
(cherry picked from commit 8816c5db220f518ef70beec7ac543290e3d5c0c7
in virt-v2v)
---
v2v/rhv-upload-plugin.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index 7f62b4e3b..f13405df1 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -161,7 +161,7 @@ def open(readonly):
endt = time.time() + timeout
while True:
- time.sleep(5)
+ time.sleep(1)
disk = disk_service.get()
if disk.status == types.DiskStatus.OK:
break
@@ -196,7 +196,7 @@ def open(readonly):
if time.time() > endt:
raise RuntimeError("timed out waiting for transfer status "
"!= INITIALIZING")
- time.sleep(5)
+ time.sleep(1)
# Now we have permission to start the transfer.
if params['rhv_direct']:
--
2.26.2

View File

@ -1,108 +0,0 @@
From 81a9e4f428e9a2305a2ea8c576dadde60fa5a381 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Thu, 20 Sep 2018 12:42:59 +0100
Subject: [PATCH] tools: Link OCaml programs with -runtime-variant _pic if
available.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
OCaml has a small runtime which is statically linked into the virt
tools (providing things like GC and primitives). Since OCaml 4.03 it
has been possible to select variants of this runtime, one of which is
compiled with -fPIC, using ocamlopt -runtime-variant _pic.
This has performance implications on i686, but is relatively free on
other architectures. Since it (in theory) adds to the security of the
final binary this commit enables it whenever it is available.
(cherry picked from commit 09abb9c990f6e07b3577088522b8ad9fb439a80e)
---
.gitignore | 1 +
configure.ac | 2 ++
m4/guestfs-ocaml.m4 | 18 ++++++++++++++++++
ocaml-link.sh => ocaml-link.sh.in | 8 +++++++-
4 files changed, 28 insertions(+), 1 deletion(-)
rename ocaml-link.sh => ocaml-link.sh.in (88%)
diff --git a/.gitignore b/.gitignore
index af80e36d1..89b8baa17 100644
--- a/.gitignore
+++ b/.gitignore
@@ -410,6 +410,7 @@ Makefile.in
/make-fs/virt-make-fs.1
/missing
/ocaml-dep.sh
+/ocaml-link.sh
/ocaml/bindtests.bc
/ocaml/bindtests.opt
/ocaml/bindtests.ml
diff --git a/configure.ac b/configure.ac
index 4da3bd021..6c38406bb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -198,6 +198,8 @@ AC_CONFIG_FILES([installcheck.sh],
[chmod +x,-w installcheck.sh])
AC_CONFIG_FILES([ocaml-dep.sh],
[chmod +x,-w ocaml-dep.sh])
+AC_CONFIG_FILES([ocaml-link.sh],
+ [chmod +x,-w ocaml-link.sh])
AC_CONFIG_FILES([p2v/virt-p2v-make-disk],
[chmod +x,-w p2v/virt-p2v-make-disk])
AC_CONFIG_FILES([p2v/virt-p2v-make-kickstart],
diff --git a/m4/guestfs-ocaml.m4 b/m4/guestfs-ocaml.m4
index e08f40a02..fea11a334 100644
--- a/m4/guestfs-ocaml.m4
+++ b/m4/guestfs-ocaml.m4
@@ -59,6 +59,24 @@ AM_CONDITIONAL([HAVE_OCAMLOPT],
AM_CONDITIONAL([HAVE_OCAMLDOC],
[test "x$OCAMLDOC" != "xno"])
+dnl Check if ocamlc/ocamlopt -runtime-variant _pic works. It was
+dnl added in OCaml >= 4.03, but in theory might be disabled by
+dnl downstream distros.
+OCAML_RUNTIME_VARIANT_PIC_OPTION=""
+if test "x$OCAMLC" != "xno"; then
+ AC_MSG_CHECKING([if OCaml -runtime-variant _pic works])
+ rm -f conftest.ml contest
+ echo 'print_endline "hello world"' > conftest.ml
+ if $OCAMLC conftest.ml -runtime-variant _pic -o conftest >&5 2>&5 ; then
+ AC_MSG_RESULT([yes])
+ OCAML_RUNTIME_VARIANT_PIC_OPTION="-runtime-variant _pic"
+ else
+ AC_MSG_RESULT([no])
+ fi
+ rm -f conftest.ml contest
+fi
+AC_SUBST([OCAML_RUNTIME_VARIANT_PIC_OPTION])
+
dnl Check if ocamldep has options -all and -one-line (not present in RHEL 6).
AC_MSG_CHECKING([if ocamldep has the -all option])
if ocamldep -all >&AS_MESSAGE_LOG_FD 2>&1; then
diff --git a/ocaml-link.sh b/ocaml-link.sh.in
similarity index 88%
rename from ocaml-link.sh
rename to ocaml-link.sh.in
index 855637534..fbcc07951 100755
--- a/ocaml-link.sh
+++ b/ocaml-link.sh.in
@@ -1,4 +1,6 @@
#!/bin/bash -
+# Script used to link OCaml programs.
+# @configure_input@
# (C) Copyright 2015-2018 Red Hat Inc.
#
# This program is free software; you can redistribute it and/or modify
@@ -41,4 +43,8 @@ while true ; do
esac
done
-exec "$@" -linkpkg -cclib "${cclib}"
+# NB -cclib must come last.
+exec "$@" \
+ @OCAML_RUNTIME_VARIANT_PIC_OPTION@ \
+ -linkpkg \
+ -cclib "${cclib}"
--
2.21.0

View File

@ -0,0 +1,31 @@
From 7fd1c3be6bb744a93eff6ae1a9cfcdd9280cf247 Mon Sep 17 00:00:00 2001
From: Nir Soffer <nirsof@gmail.com>
Date: Mon, 18 Nov 2019 23:53:46 +0200
Subject: [PATCH] rhv-upload: Show transfer id in error message
(cherry picked from commit d4ca9b6ca42d4ad3c717f5c59402ca6ff5d322bb
in virt-v2v)
---
v2v/rhv-upload-plugin.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index f13405df1..9b83d1cfa 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -194,8 +194,10 @@ def open(readonly):
if transfer.phase != types.ImageTransferPhase.INITIALIZING:
break
if time.time() > endt:
- raise RuntimeError("timed out waiting for transfer status "
- "!= INITIALIZING")
+ raise RuntimeError(
+ "timed out waiting for transfer %s status != INITIALIZING"
+ % transfer.id)
+
time.sleep(1)
# Now we have permission to start the transfer.
--
2.26.2

View File

@ -1,328 +0,0 @@
From 7423e43ec2cd27d52650a1caeb7c0576350e0a78 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Thu, 20 Sep 2018 12:59:44 +0100
Subject: [PATCH] tools: Ensure CFLAGS and LDFLAGS are passed to all OCaml
binaries (RHBZ#1624130).
After this commit, all annocheck errors are fixed except for:
Hardened: virt-get-kernel: MAYB: Gaps were detected in the annobin coverage. Run with -v to list.
After discussion with the annocheck maintainers this gap in coverage
(which corresponds to the OCaml runtime) seems to be caused either by
the runtime not being linked with the right flags, or might be a bug
in annocheck itself. In any case it's not something that can be
resolved within the scope of libguestfs.
(cherry picked from commit 34c23403c51a4d59d826c8045e06f9aabc2ceb16)
---
builder/Makefile.am | 2 +-
common/mlaugeas/Makefile.am | 2 +-
common/mlgettext/Makefile.am | 2 +-
common/mlpcre/Makefile.am | 2 +-
common/mlprogress/Makefile.am | 2 +-
common/mlstdutils/Makefile.am | 2 +-
common/mltools/Makefile.am | 2 +-
common/mlutils/Makefile.am | 2 +-
common/mlvisit/Makefile.am | 2 +-
common/mlxml/Makefile.am | 2 +-
customize/Makefile.am | 2 +-
daemon/Makefile.am | 2 +-
dib/Makefile.am | 2 +-
generator/Makefile.am | 2 +-
get-kernel/Makefile.am | 2 +-
ocaml-link.sh.in | 2 +-
ocaml/Makefile.am | 2 +-
resize/Makefile.am | 2 +-
sparsify/Makefile.am | 2 +-
sysprep/Makefile.am | 2 +-
v2v/Makefile.am | 2 +-
v2v/test-harness/Makefile.am | 2 +-
22 files changed, 22 insertions(+), 22 deletions(-)
diff --git a/builder/Makefile.am b/builder/Makefile.am
index c7b50778a..a30a229b2 100644
--- a/builder/Makefile.am
+++ b/builder/Makefile.am
@@ -215,7 +215,7 @@ OCAMLCLIBS = \
$(LIBINTL) \
-lgnu
-OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
if !HAVE_OCAMLOPT
OBJECTS = $(BOBJECTS)
diff --git a/common/mlaugeas/Makefile.am b/common/mlaugeas/Makefile.am
index 8aa15b80e..2c1a6e0fd 100644
--- a/common/mlaugeas/Makefile.am
+++ b/common/mlaugeas/Makefile.am
@@ -61,7 +61,7 @@ BOBJECTS = $(SOURCES_ML:.ml=.cmo)
XOBJECTS = $(BOBJECTS:.cmo=.cmx)
OCAMLPACKAGES =
-OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
if !HAVE_OCAMLOPT
OBJECTS = $(BOBJECTS)
diff --git a/common/mlgettext/Makefile.am b/common/mlgettext/Makefile.am
index cdcea33ec..b918f90c3 100644
--- a/common/mlgettext/Makefile.am
+++ b/common/mlgettext/Makefile.am
@@ -60,7 +60,7 @@ if HAVE_OCAML_PKG_GETTEXT
OCAMLPACKAGES += -package gettext-stub
endif
-OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
if !HAVE_OCAMLOPT
OBJECTS = $(BOBJECTS)
diff --git a/common/mlpcre/Makefile.am b/common/mlpcre/Makefile.am
index f9699f592..6f04256da 100644
--- a/common/mlpcre/Makefile.am
+++ b/common/mlpcre/Makefile.am
@@ -70,7 +70,7 @@ OCAMLPACKAGES = \
-I $(builddir)
OCAMLPACKAGES_TESTS = $(MLPCRE_CMA)
-OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
if !HAVE_OCAMLOPT
OBJECTS = $(BOBJECTS)
diff --git a/common/mlprogress/Makefile.am b/common/mlprogress/Makefile.am
index be88ef2de..af006d228 100644
--- a/common/mlprogress/Makefile.am
+++ b/common/mlprogress/Makefile.am
@@ -76,7 +76,7 @@ OCAMLPACKAGES = \
-I $(top_builddir)/ocaml \
-I $(builddir)
-OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
if !HAVE_OCAMLOPT
OBJECTS = $(BOBJECTS)
diff --git a/common/mlstdutils/Makefile.am b/common/mlstdutils/Makefile.am
index e38230db8..75252eb46 100644
--- a/common/mlstdutils/Makefile.am
+++ b/common/mlstdutils/Makefile.am
@@ -79,7 +79,7 @@ if HAVE_OCAML_PKG_OUNIT
OCAMLPACKAGES_TESTS += -package oUnit
endif
-OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
if !HAVE_OCAMLOPT
OBJECTS = $(BOBJECTS)
diff --git a/common/mltools/Makefile.am b/common/mltools/Makefile.am
index 66b18f5de..b326cf56a 100644
--- a/common/mltools/Makefile.am
+++ b/common/mltools/Makefile.am
@@ -131,7 +131,7 @@ OCAMLCLIBS = \
$(LIBINTL) \
-lgnu
-OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
if !HAVE_OCAMLOPT
OBJECTS = $(BOBJECTS)
diff --git a/common/mlutils/Makefile.am b/common/mlutils/Makefile.am
index 8627e5b10..77feafa56 100644
--- a/common/mlutils/Makefile.am
+++ b/common/mlutils/Makefile.am
@@ -74,7 +74,7 @@ OCAMLPACKAGES = \
-I $(top_builddir)/common/mlstdutils \
-I $(builddir)
-OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
if !HAVE_OCAMLOPT
OBJECTS = $(BOBJECTS)
diff --git a/common/mlvisit/Makefile.am b/common/mlvisit/Makefile.am
index add1fe56e..7230415e7 100644
--- a/common/mlvisit/Makefile.am
+++ b/common/mlvisit/Makefile.am
@@ -80,7 +80,7 @@ OCAMLPACKAGES = \
-I $(builddir)
OCAMLPACKAGES_TESTS = $(MLVISIT_CMA)
-OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
if !HAVE_OCAMLOPT
OBJECTS = $(BOBJECTS)
diff --git a/common/mlxml/Makefile.am b/common/mlxml/Makefile.am
index eab036b82..7f36b743a 100644
--- a/common/mlxml/Makefile.am
+++ b/common/mlxml/Makefile.am
@@ -72,7 +72,7 @@ OCAMLPACKAGES = \
-I $(top_builddir)/gnulib/lib/.libs \
-I $(builddir)
-OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
if !HAVE_OCAMLOPT
OBJECTS = $(BOBJECTS)
diff --git a/customize/Makefile.am b/customize/Makefile.am
index efdd27227..69cf6c13f 100644
--- a/customize/Makefile.am
+++ b/customize/Makefile.am
@@ -173,7 +173,7 @@ OCAMLCLIBS = \
$(LIBINTL) \
-lgnu
-OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
virt_customize_DEPENDENCIES = \
$(top_srcdir)/ocaml-link.sh \
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index d9ed5625e..dcae1a66c 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -347,7 +347,7 @@ OCAMLPACKAGES = \
-I $(top_builddir)/common/mlpcre/.libs \
-I $(top_builddir)/gnulib/lib/.libs
-OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
if !HAVE_OCAMLOPT
OBJECTS = $(BOBJECTS)
diff --git a/dib/Makefile.am b/dib/Makefile.am
index 316f49903..7c2ab09d6 100644
--- a/dib/Makefile.am
+++ b/dib/Makefile.am
@@ -99,7 +99,7 @@ OCAMLCLIBS = \
$(LIBINTL) \
-lgnu
-OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
if !HAVE_OCAMLOPT
OBJECTS = $(BOBJECTS)
diff --git a/generator/Makefile.am b/generator/Makefile.am
index c2d10966a..056d01346 100644
--- a/generator/Makefile.am
+++ b/generator/Makefile.am
@@ -175,7 +175,7 @@ OCAMLPACKAGES = \
-I . \
-I $(top_srcdir)/common/mlstdutils \
-I $(top_builddir)/common/mlstdutils
-OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
noinst_PROGRAM = generator
diff --git a/get-kernel/Makefile.am b/get-kernel/Makefile.am
index 81dfb48b4..75379e21f 100644
--- a/get-kernel/Makefile.am
+++ b/get-kernel/Makefile.am
@@ -82,7 +82,7 @@ OCAMLCLIBS = \
$(LIBINTL) \
-lgnu
-OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
if !HAVE_OCAMLOPT
OBJECTS = $(BOBJECTS)
diff --git a/ocaml-link.sh.in b/ocaml-link.sh.in
index fbcc07951..6819c641e 100755
--- a/ocaml-link.sh.in
+++ b/ocaml-link.sh.in
@@ -47,4 +47,4 @@ done
exec "$@" \
@OCAML_RUNTIME_VARIANT_PIC_OPTION@ \
-linkpkg \
- -cclib "${cclib}"
+ -cclib "@LDFLAGS@ $cclib"
diff --git a/ocaml/Makefile.am b/ocaml/Makefile.am
index b0f2900f2..752fc109c 100644
--- a/ocaml/Makefile.am
+++ b/ocaml/Makefile.am
@@ -37,7 +37,7 @@ CLEANFILES += t/*.annot t/*.cmi t/*.cmo t/*.cmx t/*.o t/*.a t/*.so
if HAVE_OCAML
-OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
noinst_DATA = mlguestfs.cma META
if HAVE_OCAMLOPT
diff --git a/resize/Makefile.am b/resize/Makefile.am
index 847fb313a..7a4367023 100644
--- a/resize/Makefile.am
+++ b/resize/Makefile.am
@@ -80,7 +80,7 @@ OCAMLCLIBS = \
$(LIBINTL) \
-lgnu
-OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
if !HAVE_OCAMLOPT
OBJECTS = $(BOBJECTS)
diff --git a/sparsify/Makefile.am b/sparsify/Makefile.am
index 2ab357a68..2dce5e582 100644
--- a/sparsify/Makefile.am
+++ b/sparsify/Makefile.am
@@ -88,7 +88,7 @@ OCAMLCLIBS = \
$(LIBINTL) \
-lgnu
-OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
if !HAVE_OCAMLOPT
OBJECTS = $(BOBJECTS)
diff --git a/sysprep/Makefile.am b/sysprep/Makefile.am
index 0cc9da80a..6ed4ac713 100644
--- a/sysprep/Makefile.am
+++ b/sysprep/Makefile.am
@@ -136,7 +136,7 @@ OCAMLCLIBS = \
$(LIBINTL) \
-lgnu
-OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
if !HAVE_OCAMLOPT
OBJECTS = $(BOBJECTS)
diff --git a/v2v/Makefile.am b/v2v/Makefile.am
index 7de050b06..7a1ac329e 100644
--- a/v2v/Makefile.am
+++ b/v2v/Makefile.am
@@ -201,7 +201,7 @@ OCAMLCLIBS = \
$(LIBINTL) \
-lgnu
-OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
if !HAVE_OCAMLOPT
OBJECTS = $(BOBJECTS)
diff --git a/v2v/test-harness/Makefile.am b/v2v/test-harness/Makefile.am
index d69188969..22c3b8c49 100644
--- a/v2v/test-harness/Makefile.am
+++ b/v2v/test-harness/Makefile.am
@@ -47,7 +47,7 @@ OCAMLPACKAGES = \
-I $(top_builddir)/common/mltools \
-I $(top_builddir)/v2v
-OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR)
+OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
BOBJECTS = \
$(SOURCES_ML:.ml=.cmo) \
--
2.21.0

View File

@ -1,40 +0,0 @@
From 57ed1fc4281462e02604b0e740c4ffa31cf93afb Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Thu, 27 Sep 2018 15:51:01 +0200
Subject: [PATCH] ocaml: make sure to pass LDFLAGS to ocamlmklibs linker
(RHBZ#1624130)
Pass the LDFLAGS properly as arguments for the C linker when using
ocamlmklibs via the -ldopt option.
Followup of commit 34c23403c51a4d59d826c8045e06f9aabc2ceb16.
(cherry picked from commit 4ff573c352973036b722ec0c9bf79be958b83b2c)
---
ocaml/Makefile.am | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/ocaml/Makefile.am b/ocaml/Makefile.am
index 752fc109c..4d13eed97 100644
--- a/ocaml/Makefile.am
+++ b/ocaml/Makefile.am
@@ -64,14 +64,14 @@ endif
stamp-mlguestfs: libguestfsocaml.a $(guestfs_cmm)
$(OCAMLMKLIB) -o mlguestfs \
+ -ldopt '$(LDFLAGS)' \
$(libguestfsocaml_a_OBJECTS) guestfs.cmo \
- $(LDFLAGS) \
$(LTLIBINTL) \
-L../lib/.libs -lguestfs
if HAVE_OCAMLOPT
$(OCAMLMKLIB) -o mlguestfs \
+ -ldopt '$(LDFLAGS)' \
$(libguestfsocaml_a_OBJECTS) guestfs.cmx \
- $(LDFLAGS) \
$(LTLIBINTL) \
-L../lib/.libs -lguestfs
endif
--
2.21.0

View File

@ -0,0 +1,89 @@
From d132157c9e0b6b990cd989662f5499644508de97 Mon Sep 17 00:00:00 2001
From: Nir Soffer <nsoffer@redhat.com>
Date: Thu, 28 Nov 2019 20:36:32 +0200
Subject: [PATCH] rhv-upload: Fix waiting for transfer
We were not considering failures while initializing the transfer. In
this case the transfer phase can change to PAUSED_SYSTEM or
FINISHED_FAILURE, and transfer_url will be None, which failed the
upload with a misleading error:
RuntimeError: direct upload to host not supported, requires
ovirt-engine >= 4.2 and only works when virt-v2v is run within the
oVirt/RHV environment, eg. on an oVirt node
Change the wait loop to consider all cases:
- Transfer failed and was removed
- Transfer failed and will be removed soon
- Transfer paused by the system (cancel required)
- Unexpected transfer phase (cancel required)
- Timeout waiting for TRANSFERRING state (cancel required)
Reported-by: Xiaodai Wang
(cherry picked from commit 40e1844827e4d096b1919a2159f9effc41915a73
in virt-v2v)
---
v2v/rhv-upload-plugin.py | 41 +++++++++++++++++++++++++++++++---------
1 file changed, 32 insertions(+), 9 deletions(-)
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index 9b83d1cfa..14d4e37fb 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -185,20 +185,43 @@ def open(readonly):
# Get a reference to the created transfer service.
transfer_service = transfers_service.image_transfer_service(transfer.id)
- # After adding a new transfer for the disk, the transfer's status
- # will be INITIALIZING. Wait until the init phase is over. The
- # actual transfer can start when its status is "Transferring".
+ # Wait until transfer's phase change from INITIALIZING to TRANSFERRING. On
+ # errors transfer's phase can change to PAUSED_SYSTEM or FINISHED_FAILURE.
+ # If the transfer was paused, we need to cancel it to remove the disk,
+ # otherwise the system will remove the disk and transfer shortly after.
+
endt = time.time() + timeout
while True:
- transfer = transfer_service.get()
- if transfer.phase != types.ImageTransferPhase.INITIALIZING:
+ time.sleep(1)
+ try:
+ transfer = transfer_service.get()
+ except sdk.NotFoundError:
+ # The system has removed the disk and the transfer.
+ raise RuntimeError("transfer %s was removed" % transfer.id)
+
+ if transfer.phase == types.ImageTransferPhase.FINISHED_FAILURE:
+ # The system will remove the disk and the transfer soon.
+ raise RuntimeError(
+ "transfer %s has failed" % transfer.id)
+
+ if transfer.phase == types.ImageTransferPhase.PAUSED_SYSTEM:
+ transfer_service.cancel()
+ raise RuntimeError(
+ "transfer %s was paused by system" % transfer.id)
+
+ if transfer.phase == types.ImageTransferPhase.TRANSFERRING:
break
- if time.time() > endt:
+
+ if transfer.phase != types.ImageTransferPhase.INITIALIZING:
+ transfer_service.cancel()
raise RuntimeError(
- "timed out waiting for transfer %s status != INITIALIZING"
- % transfer.id)
+ "unexpected transfer %s phase %s"
+ % (transfer.id, transfer.phase))
- time.sleep(1)
+ if time.time() > endt:
+ transfer_service.cancel()
+ raise RuntimeError(
+ "timed out waiting for transfer %s" % transfer.id)
# Now we have permission to start the transfer.
if params['rhv_direct']:
--
2.26.2

View File

@ -1,323 +0,0 @@
From 81f35e441d06bff2bf60bff6354d53de137847d9 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 19 Jun 2018 10:44:57 +0100
Subject: [PATCH] v2v: Model machine type explicitly.
QEMU for x86 supports two machine types, "pc" (emulating the ancient
Intel i440FX chipset originally used by the Pentium Pro), and "q35"
(https://wiki.qemu.org/Features/Q35).
Currently virt-v2v does not set any machine type, so libvirt or the
target hypervisor will choose some default, probably i440fx. The
latest advice from the QEMU and libvirt communities is not to rely on
the default machine type but to specify what we need explicitly, but
it may also be that the libvirt configuration file has been changed to
set the default machine type to Q35 (either by the distro or the end
user).
None of this matters for reasonably new guests since they can boot
with either chipset. However there are some very old guests (notably
Windows XP) which cannot handle Q35.
This commit changes virt-v2v so it always tries to specify the machine
type explicitly (assuming the target supports that, and not all of
them do). For x86_64 guests this patch always selects i440fx (pc).
In future we hope to get the correct machine type for the guest from
libosinfo but this is not available yet.
For non-x86 architectures we select the "virt" model which will
probably only work for AArch64. More work is needed for POWER.
For secure boot we still have to force the machine type to Q35. In a
future version this forcing can be removed since any guest which is
using secure boot will be new enough that it'll be using Q35 anyway
(on x86).
(cherry picked from commit 55879b2f2c5b205352f48f999e20efd9b455ea43)
---
v2v/convert_linux.ml | 7 +++++++
v2v/convert_windows.ml | 7 +++++++
v2v/create_libvirt_xml.ml | 37 +++++++++++++++++++++++++------------
v2v/create_ovf.ml | 2 ++
v2v/output_glance.ml | 5 +++++
v2v/output_qemu.ml | 30 +++++++++++++++++++-----------
v2v/test-v2v-i-ova.xml | 2 +-
v2v/types.ml | 8 ++++++++
v2v/types.mli | 6 ++++--
9 files changed, 78 insertions(+), 26 deletions(-)
diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml
index 4a7447fe1..fd6b71ba4 100644
--- a/v2v/convert_linux.ml
+++ b/v2v/convert_linux.ml
@@ -122,6 +122,12 @@ let convert (g : G.guestfs) inspect source output rcaps =
SELinux_relabel.relabel g;
+ (* XXX Look up this information in libosinfo in future. *)
+ let machine =
+ match inspect.i_arch with
+ | "i386"|"x86_64" -> I440FX
+ | _ -> Virt in
+
(* Return guest capabilities from the convert () function. *)
let guestcaps = {
gcaps_block_bus = block_type;
@@ -130,6 +136,7 @@ let convert (g : G.guestfs) inspect source output rcaps =
gcaps_virtio_rng = kernel.ki_supports_virtio_rng;
gcaps_virtio_balloon = kernel.ki_supports_virtio_balloon;
gcaps_isa_pvpanic = kernel.ki_supports_isa_pvpanic;
+ gcaps_machine = machine;
gcaps_arch = Utils.kvm_arch inspect.i_arch;
gcaps_acpi = acpi;
} in
diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml
index 163319545..1e058136e 100644
--- a/v2v/convert_windows.ml
+++ b/v2v/convert_windows.ml
@@ -212,6 +212,12 @@ let convert (g : G.guestfs) inspect source output rcaps =
warning (f_"this guest has Anti-Virus (AV) software and a new virtio block device driver was installed. In some circumstances, AV may prevent new drivers from working (resulting in a 7B boot error). If this happens, try disabling AV before doing the conversion.");
);
+ (* XXX Look up this information in libosinfo in future. *)
+ let machine =
+ match inspect.i_arch with
+ | "i386"|"x86_64" -> I440FX
+ | _ -> Virt in
+
(* Return guest capabilities from the convert () function. *)
let guestcaps = {
gcaps_block_bus = block_driver;
@@ -220,6 +226,7 @@ let convert (g : G.guestfs) inspect source output rcaps =
gcaps_virtio_rng = virtio_rng_supported;
gcaps_virtio_balloon = virtio_ballon_supported;
gcaps_isa_pvpanic = isa_pvpanic_supported;
+ gcaps_machine = machine;
gcaps_arch = Utils.kvm_arch inspect.i_arch;
gcaps_acpi = true;
} in
diff --git a/v2v/create_libvirt_xml.ml b/v2v/create_libvirt_xml.ml
index fbe90eeaa..8a34c94b0 100644
--- a/v2v/create_libvirt_xml.ml
+++ b/v2v/create_libvirt_xml.ml
@@ -81,15 +81,17 @@ let create_libvirt_xml ?pool source target_buses guestcaps
match target_firmware with
| TargetBIOS -> None
| TargetUEFI -> Some (find_uefi_firmware guestcaps.gcaps_arch) in
- let secure_boot_required =
- match uefi_firmware with
- | Some { Uefi.flags = flags }
- when List.mem Uefi.UEFI_FLAG_SECURE_BOOT_REQUIRED flags -> true
- | _ -> false in
- (* Currently these are required by secure boot, but in theory they
- * might be independent properties.
- *)
- let machine_q35 = secure_boot_required in
+ let machine, secure_boot_required =
+ match guestcaps.gcaps_machine, uefi_firmware with
+ | _, Some { Uefi.flags = flags }
+ when List.mem Uefi.UEFI_FLAG_SECURE_BOOT_REQUIRED flags ->
+ (* Force machine type to Q35 because PC does not support
+ * secure boot. We must remove this when we get the
+ * correct machine type from libosinfo in future. XXX
+ *)
+ Q35, true
+ | machine, _ ->
+ machine, false in
let smm = secure_boot_required in
(* We have the machine features of the guest when it was on the
@@ -140,7 +142,18 @@ let create_libvirt_xml ?pool source target_buses guestcaps
(* The <os> section subelements. *)
let os_section =
- let machine = if machine_q35 then [ "machine", "q35" ] else [] in
+ let os = ref [] in
+
+ let machine =
+ match machine with
+ | I440FX -> "pc"
+ | Q35 -> "q35"
+ | Virt -> "virt" in
+
+ List.push_back os
+ (e "type" ["arch", guestcaps.gcaps_arch;
+ "machine", machine]
+ [PCData "hvm"]);
let loader =
match uefi_firmware with
@@ -152,8 +165,8 @@ let create_libvirt_xml ?pool source target_buses guestcaps
[ PCData code ];
e "nvram" ["template", vars_template] [] ] in
- (e "type" (["arch", guestcaps.gcaps_arch] @ machine) [PCData "hvm"])
- :: loader in
+ List.push_back_list os loader;
+ !os in
List.push_back_list body [
e "os" [] os_section;
diff --git a/v2v/create_ovf.ml b/v2v/create_ovf.ml
index 5db239d66..01970013e 100644
--- a/v2v/create_ovf.ml
+++ b/v2v/create_ovf.ml
@@ -602,6 +602,8 @@ let rec create_ovf source targets guestcaps inspect
source.s_vcpu memsize_mb)]
] in
+ (* XXX How to set machine type for Q35? *)
+
List.push_back virtual_hardware_section_items (
e "Item" [] ([
e "rasd:Caption" [] [PCData (sprintf "%d virtual cpu" source.s_vcpu)];
diff --git a/v2v/output_glance.ml b/v2v/output_glance.ml
index c334def42..96c31da59 100644
--- a/v2v/output_glance.ml
+++ b/v2v/output_glance.ml
@@ -86,6 +86,11 @@ object
(match guestcaps.gcaps_video with
| QXL -> "qxl"
| Cirrus -> "cirrus");
+ "hw_machine_type",
+ (match guestcaps.gcaps_machine with
+ | I440FX -> "pc"
+ | Q35 -> "q35"
+ | Virt -> "virt");
"architecture", guestcaps.gcaps_arch;
"hypervisor_type", "kvm";
"vm_mode", "hvm";
diff --git a/v2v/output_qemu.ml b/v2v/output_qemu.ml
index 952660de2..e23f22e12 100644
--- a/v2v/output_qemu.ml
+++ b/v2v/output_qemu.ml
@@ -56,17 +56,25 @@ object
match target_firmware with
| TargetBIOS -> None
| TargetUEFI -> Some (find_uefi_firmware guestcaps.gcaps_arch) in
- let secure_boot_required =
- match uefi_firmware with
- | Some { Uefi.flags }
- when List.mem Uefi.UEFI_FLAG_SECURE_BOOT_REQUIRED flags -> true
- | _ -> false in
- (* Currently these are required by secure boot, but in theory they
- * might be independent properties.
- *)
- let machine_q35 = secure_boot_required in
+ let machine, secure_boot_required =
+ match guestcaps.gcaps_machine, uefi_firmware with
+ | _, Some { Uefi.flags }
+ when List.mem Uefi.UEFI_FLAG_SECURE_BOOT_REQUIRED flags ->
+ (* Force machine type to Q35 because PC does not support
+ * secure boot. We must remove this when we get the
+ * correct machine type from libosinfo in future. XXX
+ *)
+ Q35, true
+ | machine, _ ->
+ machine, false in
let smm = secure_boot_required in
+ let machine =
+ match machine with
+ | I440FX -> "pc"
+ | Q35 -> "q35"
+ | Virt -> "virt" in
+
(* Construct the command line. Note that the [Qemuopts]
* module deals with shell and qemu comma quoting.
*)
@@ -80,8 +88,8 @@ object
flag "-no-user-config"; flag "-nodefaults";
arg "-name" source.s_name;
- arg_list "-machine" (if machine_q35 then ["q35"] else [] @
- if smm then ["smm=on"] else [] @
+ arg_list "-machine" (machine ::
+ (if smm then ["smm=on"] else []) @
["accel=kvm:tcg"]);
(match uefi_firmware with
diff --git a/v2v/test-v2v-i-ova.xml b/v2v/test-v2v-i-ova.xml
index 5a303b80a..b277193a8 100644
--- a/v2v/test-v2v-i-ova.xml
+++ b/v2v/test-v2v-i-ova.xml
@@ -10,7 +10,7 @@
<apic/>
</features>
<os>
- <type arch='x86_64'>hvm</type>
+ <type arch='x86_64' machine='pc'>hvm</type>
</os>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
diff --git a/v2v/types.ml b/v2v/types.ml
index bb77e5669..9851386f7 100644
--- a/v2v/types.ml
+++ b/v2v/types.ml
@@ -401,6 +401,7 @@ type guestcaps = {
gcaps_virtio_rng : bool;
gcaps_virtio_balloon : bool;
gcaps_isa_pvpanic : bool;
+ gcaps_machine : guestcaps_machine;
gcaps_arch : string;
gcaps_acpi : bool;
}
@@ -412,6 +413,7 @@ and requested_guestcaps = {
and guestcaps_block_type = Virtio_blk | Virtio_SCSI | IDE
and guestcaps_net_type = Virtio_net | E1000 | RTL8139
and guestcaps_video_type = QXL | Cirrus
+and guestcaps_machine = I440FX | Q35 | Virt
let string_of_block_type = function
| Virtio_blk -> "virtio-blk"
@@ -424,17 +426,23 @@ let string_of_net_type = function
let string_of_video = function
| QXL -> "qxl"
| Cirrus -> "cirrus"
+let string_of_machine = function
+ | I440FX -> "i440fx"
+ | Q35 -> "q35"
+ | Virt -> "virt"
let string_of_guestcaps gcaps =
sprintf "\
gcaps_block_bus = %s
gcaps_net_bus = %s
gcaps_video = %s
+gcaps_machine = %s
gcaps_arch = %s
gcaps_acpi = %b
" (string_of_block_type gcaps.gcaps_block_bus)
(string_of_net_type gcaps.gcaps_net_bus)
(string_of_video gcaps.gcaps_video)
+ (string_of_machine gcaps.gcaps_machine)
gcaps.gcaps_arch
gcaps.gcaps_acpi
diff --git a/v2v/types.mli b/v2v/types.mli
index f60e5c98f..5e33b1de9 100644
--- a/v2v/types.mli
+++ b/v2v/types.mli
@@ -240,8 +240,9 @@ type guestcaps = {
gcaps_virtio_balloon : bool; (** Guest supports virtio balloon. *)
gcaps_isa_pvpanic : bool; (** Guest supports ISA pvpanic device. *)
- gcaps_arch : string; (** Architecture that KVM must emulate. *)
- gcaps_acpi : bool; (** True if guest supports acpi. *)
+ gcaps_machine : guestcaps_machine; (** Machine model. *)
+ gcaps_arch : string; (** Architecture that KVM must emulate. *)
+ gcaps_acpi : bool; (** True if guest supports acpi. *)
}
(** Guest capabilities after conversion. eg. Was virtio found or installed? *)
@@ -257,6 +258,7 @@ and requested_guestcaps = {
and guestcaps_block_type = Virtio_blk | Virtio_SCSI | IDE
and guestcaps_net_type = Virtio_net | E1000 | RTL8139
and guestcaps_video_type = QXL | Cirrus
+and guestcaps_machine = I440FX | Q35 | Virt
val string_of_guestcaps : guestcaps -> string
val string_of_requested_guestcaps : requested_guestcaps -> string
--
2.21.0

View File

@ -0,0 +1,84 @@
From 8d39f6bcf21a7c76e29c270b9304c978bbf2e8ba Mon Sep 17 00:00:00 2001
From: Nir Soffer <nirsof@gmail.com>
Date: Fri, 1 Nov 2019 22:56:18 +0100
Subject: [PATCH] v2v: Optimize convert for images with small holes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
"qemu-img convert" detects zeroes in allocated areas and punch holes in
the destination image. This may save space on the destination image, but
slows down conversion when using outputs such as rhv-upload, which have
very large overhead per requests.
Using the -S flag, we can treat small areas filled with zeroes as data,
limiting the number of requests, and speeding the operation.
Here is an example converting Fedora 30 image:
$ virt-builder fedora-30 -o src.img
...
$ qemu-img map -f raw --output json src.img | wc -l
213
$ qemu-img convert -f raw -O raw -t none -T none src.img dst.img
$ qemu-img map -f raw --output json dst.img | wc -l
1443
$ ls -lhs *.img
1.2G -rw-r--r--. 1 nsoffer nsoffer 6.0G Nov  1 21:48 dst.img
1.2G -rw-r--r--. 1 nsoffer nsoffer 6.0G Nov  1 21:46 src.img
Qemu did 1443 writes instead of 213 (5.8X). Lets repeat this conversion
with the -S option:
$ qemu-img convert -f raw -O raw -t none -T none -S 64k src.img dst.img
$ qemu-img map -f raw --output json dst.img | wc -l
213
$ ls -lhs *.img
1.2G -rw-r--r--. 1 nsoffer nsoffer 6.0G Nov  1 21:48 dst.img
1.2G -rw-r--r--. 1 nsoffer nsoffer 6.0G Nov  1 21:46 src.img
Picking a good value for -S is not easy. Testing show that 64k is best
value for this test image for limiting the number of requests:
$ for size in 4k 8k 16k 32k 64k; do \
printf "%5s: " $size; \
qemu-img convert -f raw -O raw -t none -T none -S $size src.img dst.img; \
qemu-img map -f raw --output json dst.img | wc -l; \
done
   4k: 1443
   8k: 731
  16k: 521
  32k: 387
  64k: 213
We need more testing with oVirt to measure the performance improvement
and pick a good value. This should probably be an option, but lets start
with a minimal change.
(cherry picked from commit 2aa78ade2d48e926b7b04050338ebd8a0c5e3f05
in virt-v2v)
---
v2v/v2v.ml | 1 +
1 file changed, 1 insertion(+)
diff --git a/v2v/v2v.ml b/v2v/v2v.ml
index d7a868659..a81a2320a 100644
--- a/v2v/v2v.ml
+++ b/v2v/v2v.ml
@@ -754,6 +754,7 @@ and copy_targets cmdline targets input output =
(if not (quiet ()) then [ "-p" ] else []) @
[ "-n"; "-f"; "qcow2"; "-O"; t.target_format ] @
(if cmdline.compressed then [ "-c" ] else []) @
+ [ "-S"; "64k" ] @
[ overlay_file; filename ] in
let start_time = gettimeofday () in
if run_command cmd <> 0 then
--
2.26.2

View File

@ -0,0 +1,49 @@
From 49623c945c93b878d13c0539eddf2d625f5aeb3c Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Wed, 15 Jan 2020 11:12:17 +0000
Subject: [PATCH] v2v: -o rhv-upload: Make -oo rhv-cafile optional in all cases
(RHBZ#1791240).
This is actually not required, because ovirtsdk4 will use the system's
global trust store if necessary. Therefore we can make it optional in
all cases.
(cherry picked from commit 65ee9387d4be0e3c5cd214b967fef7a1a8841233
in virt-v2v)
---
v2v/output_rhv_upload.ml | 2 --
v2v/virt-v2v-output-rhv.pod | 5 ++++-
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml
index 2c8c18732..e1d06867b 100644
--- a/v2v/output_rhv_upload.ml
+++ b/v2v/output_rhv_upload.ml
@@ -81,8 +81,6 @@ let parse_output_options options =
let rhv_direct = !rhv_direct in
let rhv_verifypeer = !rhv_verifypeer in
let rhv_disk_uuids = Option.map List.rev !rhv_disk_uuids in
- if rhv_verifypeer && rhv_cafile = None then
- error (f_"-o rhv-upload: must use -oo rhv-cafile to supply the path to the oVirt or RHV users ca.pem file");
{ rhv_cafile; rhv_cluster; rhv_direct; rhv_verifypeer; rhv_disk_uuids }
diff --git a/v2v/virt-v2v-output-rhv.pod b/v2v/virt-v2v-output-rhv.pod
index 04a894268..4520c9184 100644
--- a/v2v/virt-v2v-output-rhv.pod
+++ b/v2v/virt-v2v-output-rhv.pod
@@ -101,7 +101,10 @@ The storage domain.
The F<ca.pem> file (Certificate Authority), copied from
F</etc/pki/ovirt-engine/ca.pem> on the oVirt engine.
-This option must be specified if I<-oo rhv-verifypeer> is enabled.
+If I<-oo rhv-verifypeer> is enabled then this option can
+be used to control which CA is used to verify the clients
+identity. If this option is not used then the systems
+global trust store is used.
=item I<-oo rhv-cluster=>C<CLUSTERNAME>
--
2.26.2

View File

@ -1,37 +0,0 @@
From 8a4072c4b16e20c6ac55cbf350bfae2d0d1c7a0b Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Mon, 3 Sep 2018 15:24:05 +0100
Subject: [PATCH] v2v: windows: Fix rhev-apt command line (RHBZ#1624902).
See:
https://bugzilla.redhat.com/show_bug.cgi?id=1584678#c15
Fixes commit bcdbe6405c10ecb7374ae47eee6385be17dbd49e. However this
bug was copied directly from old virt-v2v which did the same thing
(from lib/Sys/VirtConvert/Converter/Windows.pm):
echo installing rhev-apt >>log.txt
"rhev-apt.exe" /S /v /qn >>log.txt
Thanks: Lev Veyde
(cherry picked from commit e12c56176abcc2d970a35f83bffc95f7ad1b2aab)
---
v2v/convert_windows.ml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml
index 1e058136e..0346ba4fe 100644
--- a/v2v/convert_windows.ml
+++ b/v2v/convert_windows.ml
@@ -347,7 +347,7 @@ echo Wait for PnP to complete
@echo off
echo installing rhev-apt
-\"\\rhev-apt.exe\" /S /v /qn
+\"\\rhev-apt.exe\" /S /v/qn
echo starting rhev-apt
net start rhev-apt
--
2.21.0

View File

@ -0,0 +1,33 @@
From 03b67600b98e8af2ea199f8643b2993c1effc60f Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Wed, 15 Jan 2020 10:55:27 +0000
Subject: [PATCH] docs: Fix update-crypto-policies command (RHBZ#1791257).
The command as documented was wrong. We need to use the --set option
to change the policy.
Fixes commit d5cbe7b4bee5dec9e28b1db03e933c97ef6d11e0.
Thanks: Xiaodai Wang
(cherry picked from commit 0edf419e983fe75daef9eaa7bd0578cbcada2e73
in virt-v2v)
---
v2v/virt-v2v-input-xen.pod | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/v2v/virt-v2v-input-xen.pod b/v2v/virt-v2v-input-xen.pod
index 4bb5d2dc2..9fd5065f1 100644
--- a/v2v/virt-v2v-input-xen.pod
+++ b/v2v/virt-v2v-input-xen.pod
@@ -37,7 +37,7 @@ to interoperate with RHEL 5 sshd are disabled. To enable them you may
need to run this command on the conversion server (ie. ssh client),
but read L<update-crypto-policies(8)> first:
- # update-crypto-policies LEGACY
+ # update-crypto-policies --set LEGACY
=head2 Test libvirt connection to remote Xen host
--
2.26.2

View File

@ -1,40 +0,0 @@
From 4d78c436b15742c25288bcae441a9782ee316fe5 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Mon, 3 Sep 2018 14:30:21 +0100
Subject: [PATCH] v2v: docs: Describe support for SHA-2 certs for Windows 7 /
2008 R2 (RHBZ#1624878).
Thanks: Yan Vugenfirer.
(cherry picked from commit 741ef228cd8d17bd1a8a60a2cfa83c3937120ede)
---
v2v/virt-v2v.pod | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
index 893e47fb9..dc443b717 100644
--- a/v2v/virt-v2v.pod
+++ b/v2v/virt-v2v.pod
@@ -1097,6 +1097,20 @@ This can also prevent booting with a 7B error [see previous section]
if the guest has group policy containing
C<Device Installation Restrictions>.
+=head2 Support for SHA-2 certificates in Windows 7 and Windows Server 2008 R2
+
+Later versions of the Windows virtio drivers are signed using SHA-2
+certificates (instead of SHA-1). The original shipping Windows 7 and
+Windows Server 2008 R2 did not understand SHA-2 certificates and so
+the Windows virtio drivers will not install properly.
+
+To fix this you must apply SHA-2 Code Signing Support from:
+L<https://docs.microsoft.com/en-us/security-updates/SecurityAdvisories/2015/3033929>
+before converting the guest.
+
+For further information see:
+L<https://bugzilla.redhat.com/show_bug.cgi?id=1624878>
+
=head1 UEFI
VMware allows you to present UEFI firmware to guests (instead of the
--
2.21.0

Some files were not shown because too many files have changed in this diff Show More