mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
Remove virt-p2v
This removes only the tool itself, and all the bits strictly needed to not break the build. This is now available as separate tool in its own repository: https://github.com/libguestfs/virt-p2v
This commit is contained in:
@@ -110,9 +110,6 @@ SUBDIRS += fish
|
||||
|
||||
# virt-tools in C.
|
||||
SUBDIRS += align cat diff df edit format inspector make-fs rescue
|
||||
if HAVE_P2V
|
||||
SUBDIRS += common/miniexpect p2v
|
||||
endif
|
||||
|
||||
# bash-completion
|
||||
SUBDIRS += bash
|
||||
|
||||
13
configure.ac
13
configure.ac
@@ -213,12 +213,6 @@ 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],
|
||||
[chmod +x,-w p2v/virt-p2v-make-kickstart])
|
||||
AC_CONFIG_FILES([p2v/virt-p2v-make-kiwi],
|
||||
[chmod +x,-w p2v/virt-p2v-make-kiwi])
|
||||
AC_CONFIG_FILES([php/extension/php-for-tests.sh],
|
||||
[chmod +x,-w php/extension/php-for-tests.sh])
|
||||
AC_CONFIG_FILES([pick-guests.pl],
|
||||
@@ -298,7 +292,6 @@ AC_CONFIG_FILES([Makefile
|
||||
ocaml/META
|
||||
ocaml/Makefile
|
||||
ocaml/examples/Makefile
|
||||
p2v/Makefile
|
||||
perl/Build.PL
|
||||
perl/Makefile
|
||||
perl/examples/Makefile
|
||||
@@ -381,10 +374,6 @@ AC_CONFIG_FILES([Makefile
|
||||
v2v/test-harness/META
|
||||
website/index.html])
|
||||
|
||||
if test "x$HAVE_P2V_TRUE" = "x"; then
|
||||
AC_CONFIG_COMMANDS([p2v/p2v-config.h], [${ac_srcdir}/p2v/generate-p2v-config.pl --file=p2v-config.h --output=p2v/p2v-config.h])
|
||||
fi
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
dnl Produce summary.
|
||||
@@ -403,8 +392,6 @@ echo "FUSE filesystem ..................... $enable_fuse"
|
||||
echo "Default backend ..................... $DEFAULT_BACKEND"
|
||||
AS_ECHO_N(["GNU gettext for i18n ................ "])
|
||||
if test "x$HAVE_GNU_GETTEXT_TRUE" = "x"; then echo "yes"; else echo "no"; fi
|
||||
AS_ECHO_N(["virt-p2v ............................ "])
|
||||
if test "x$HAVE_P2V_TRUE" = "x"; then echo "yes"; else echo "no"; fi
|
||||
AS_ECHO_N(["OCaml bindings ...................... "])
|
||||
if test "x$HAVE_OCAML_TRUE" = "x"; then echo "yes"; else echo "no"; fi
|
||||
AS_ECHO_N(["OCaml-based virt tools .............. "])
|
||||
|
||||
@@ -75,8 +75,6 @@ Run it from the top source directory using the command
|
||||
|
||||
output_to "AUTHORS"
|
||||
Authors.generate_authors;
|
||||
output_to "p2v/AUTHORS"
|
||||
Authors.generate_p2v_authors;
|
||||
|
||||
output_to "common/errnostring/errnostring-gperf.gperf"
|
||||
Errnostring.generate_errnostring_gperf;
|
||||
|
||||
@@ -61,9 +61,6 @@ cp @bindir@/virt-get-kernel get-kernel/
|
||||
cp @bindir@/virt-inspector inspector/
|
||||
cp @bindir@/virt-ls cat/
|
||||
cp @bindir@/virt-make-fs make-fs/
|
||||
cp @libdir@/virt-p2v/virt-p2v.xz p2v/
|
||||
unxz -fk p2v/virt-p2v.xz
|
||||
chmod +x p2v/virt-p2v
|
||||
cp @bindir@/virt-rescue rescue/
|
||||
cp @bindir@/virt-resize resize/
|
||||
cp @bindir@/virt-sparsify sparsify/
|
||||
|
||||
49
p2v/.gitignore
vendored
49
p2v/.gitignore
vendored
@@ -1,49 +0,0 @@
|
||||
*~
|
||||
*.log
|
||||
*.o
|
||||
*.trs
|
||||
.deps
|
||||
.libs
|
||||
Makefile
|
||||
Makefile.in
|
||||
|
||||
/about-authors.c
|
||||
/AUTHORS
|
||||
/blank-part.img
|
||||
/config.c
|
||||
/dependencies.archlinux
|
||||
/dependencies.debian
|
||||
/dependencies.redhat
|
||||
/dependencies.suse
|
||||
/fedora.img
|
||||
/kernel-config.c
|
||||
/p2v-config.h
|
||||
/stamp-test-virt-p2v-pxe-data-files
|
||||
/stamp-test-virt-p2v-pxe-hostkey
|
||||
/stamp-test-virt-p2v-pxe-kernel
|
||||
/stamp-test-virt-p2v-pxe-userkey
|
||||
/stamp-virt-p2v.pod
|
||||
/stamp-virt-p2v-make-disk.pod
|
||||
/stamp-virt-p2v-make-kickstart.pod
|
||||
/stamp-virt-p2v-make-kiwi.pod
|
||||
/test-virt-p2v-pxe.authorized_keys
|
||||
/test-virt-p2v-pxe.id_rsa
|
||||
/test-virt-p2v-pxe.id_rsa.pub
|
||||
/test-virt-p2v-pxe.img
|
||||
/test-virt-p2v-pxe.initramfs
|
||||
/test-virt-p2v-pxe.sshd_config
|
||||
/test-virt-p2v-pxe.ssh_host_rsa_key
|
||||
/test-virt-p2v-pxe.ssh_host_rsa_key.pub
|
||||
/test-virt-p2v-pxe.vmlinuz
|
||||
/virt-p2v
|
||||
/virt-p2v.1
|
||||
/virt-p2v.i686
|
||||
/virt-p2v.img
|
||||
/virt-p2v-kernel-config.pod
|
||||
/virt-p2v-make-disk
|
||||
/virt-p2v-make-disk.1
|
||||
/virt-p2v-make-kickstart
|
||||
/virt-p2v-make-kickstart.1
|
||||
/virt-p2v-make-kiwi
|
||||
/virt-p2v-make-kiwi.1
|
||||
/virt-p2v.xz
|
||||
376
p2v/Makefile.am
376
p2v/Makefile.am
@@ -1,376 +0,0 @@
|
||||
# libguestfs virt-p2v
|
||||
# Copyright (C) 2009-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.
|
||||
|
||||
include $(top_srcdir)/subdir-rules.mk
|
||||
|
||||
generator_built = \
|
||||
AUTHORS
|
||||
|
||||
BUILT_SOURCES = \
|
||||
$(generator_built)
|
||||
|
||||
EXTRA_DIST = \
|
||||
.gitignore \
|
||||
$(BUILT_SOURCES) \
|
||||
$(TESTS) $(APPLIANCE_TESTS) $(SLOW_TESTS) \
|
||||
contrib/aux-scripts/do-build.sh \
|
||||
contrib/build-p2v-iso.sh \
|
||||
contrib/patches/0001-RHEL-5-ONLY-DISABLE-AUTOMATIC-REMOTE-PORT-ALLOCATION.patch \
|
||||
contrib/patches/0002-RHEL-5-ONLY-QEMU-NBD-1.4-HAS-NO-f-OPTION.patch \
|
||||
contrib/test-p2v-iso.sh \
|
||||
dependencies.m4 \
|
||||
generate-p2v-authors.pl \
|
||||
generate-p2v-config.pl \
|
||||
issue \
|
||||
kiwi-config.sh \
|
||||
kiwi-config.xml.in \
|
||||
launch-virt-p2v \
|
||||
p2v.ks.in \
|
||||
p2v.service \
|
||||
test-virt-p2v-docs.sh \
|
||||
test-virt-p2v-pxe.sshd_config.in \
|
||||
test-virt-p2v-scp.sh \
|
||||
test-virt-p2v-ssh.sh \
|
||||
virt-p2v.pod \
|
||||
virt-p2v-make-disk.in \
|
||||
virt-p2v-make-disk.pod \
|
||||
virt-p2v-make-kickstart.in \
|
||||
virt-p2v-make-kickstart.pod \
|
||||
virt-p2v-make-kiwi.in \
|
||||
virt-p2v-make-kiwi.pod
|
||||
|
||||
# Don't clean ssh_host_rsa_key{,.pub} or id_rsa{,.pub} since those
|
||||
# consume system entropy to regenerate.
|
||||
CLEANFILES += \
|
||||
$(dependencies_files) \
|
||||
$(generated_sources) \
|
||||
$(PHYSICAL_MACHINE) $(BLANK_DISK) \
|
||||
about-authors.c \
|
||||
stamp-test-virt-p2v-pxe-data-files \
|
||||
stamp-test-virt-p2v-pxe-kernel \
|
||||
test-virt-p2v-pxe.authorized_keys \
|
||||
test-virt-p2v-pxe.img \
|
||||
test-virt-p2v-pxe.vmlinuz \
|
||||
test-virt-p2v-pxe.initramfs \
|
||||
test-virt-p2v-pxe.sshd_config \
|
||||
virt-p2v.img \
|
||||
virt-p2v-kernel-config.pod \
|
||||
virt-p2v.xz
|
||||
|
||||
# Although virt-p2v is a regular binary, it is not usually installed
|
||||
# in /usr/bin since it only functions when contained in an ISO or PXE
|
||||
# image which is used to boot the physical machine (since otherwise
|
||||
# virt-p2v would not be able to get a consistent snapshot of the
|
||||
# physical disks). Also we don't want the naked binary to appear on
|
||||
# the host, which would cause various Gtk dependencies to be pulled
|
||||
# in, so it must be compressed.
|
||||
virtp2vlibdir = $(libdir)/virt-p2v
|
||||
virtp2vlib_DATA = virt-p2v.xz
|
||||
|
||||
virt-p2v.xz: virt-p2v
|
||||
rm -f $@ $@-t
|
||||
xz --best --keep --stdout $< > $@-t
|
||||
mv $@-t $@
|
||||
|
||||
noinst_PROGRAMS = virt-p2v
|
||||
|
||||
virt_p2v_SOURCES = \
|
||||
conversion.c \
|
||||
cpuid.c \
|
||||
gui.c \
|
||||
gui-gtk2-compat.h \
|
||||
gui-gtk3-compat.h \
|
||||
inhibit.c \
|
||||
kernel.c \
|
||||
kernel-cmdline.c \
|
||||
main.c \
|
||||
nbd.c \
|
||||
p2v.h \
|
||||
p2v-config.h \
|
||||
physical-xml.c \
|
||||
rtc.c \
|
||||
ssh.c \
|
||||
utils.c \
|
||||
whole-file.c
|
||||
|
||||
generated_sources = \
|
||||
config.c \
|
||||
kernel-config.c \
|
||||
p2v-config.h
|
||||
|
||||
nodist_virt_p2v_SOURCES = \
|
||||
$(generated_sources) \
|
||||
about-authors.c
|
||||
|
||||
virt_p2v_CPPFLAGS = \
|
||||
-DLOCALEBASEDIR=\""$(datadir)/locale"\" \
|
||||
-DGTK_DISABLE_DEPRECATED \
|
||||
-I$(top_srcdir)/common/utils -I$(top_builddir)/common/utils \
|
||||
-I$(top_srcdir)/lib -I$(top_builddir)/lib \
|
||||
-I$(top_srcdir)/common/miniexpect -I$(top_builddir)/common/miniexpect \
|
||||
-I$(srcdir)/../gnulib/lib -I../gnulib/lib
|
||||
|
||||
virt_p2v_CFLAGS = \
|
||||
-pthread \
|
||||
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
|
||||
$(PCRE_CFLAGS) \
|
||||
$(LIBXML2_CFLAGS) \
|
||||
$(GTK_CFLAGS) \
|
||||
$(DBUS_CFLAGS)
|
||||
|
||||
virt_p2v_LDADD = \
|
||||
$(top_builddir)/common/utils/libutils.la \
|
||||
$(top_builddir)/common/miniexpect/libminiexpect.la \
|
||||
$(PCRE_LIBS) \
|
||||
$(LIBXML2_LIBS) \
|
||||
$(GTK_LIBS) \
|
||||
$(DBUS_LIBS) \
|
||||
../gnulib/lib/libgnu.la \
|
||||
-lm
|
||||
|
||||
$(generated_sources) virt-p2v-kernel-config.pod: $(srcdir)/generate-p2v-config.pl
|
||||
$(AM_V_GEN)rm -f $@ $@-t && $(PERL) $(<) --file=$@ --output=$@-t && mv $@-t $@
|
||||
|
||||
about-authors.c: $(srcdir)/generate-p2v-authors.pl $(srcdir)/AUTHORS
|
||||
$(AM_V_GEN)rm -f $@ $@-t && $(PERL) $(<) $(srcdir)/AUTHORS > $@-t && mv $@-t $@
|
||||
|
||||
# Scripts to build the disk image, USB key, or kickstart.
|
||||
bin_SCRIPTS = virt-p2v-make-disk virt-p2v-make-kickstart virt-p2v-make-kiwi
|
||||
|
||||
dependencies_files = \
|
||||
dependencies.archlinux \
|
||||
dependencies.debian \
|
||||
dependencies.redhat \
|
||||
dependencies.suse
|
||||
|
||||
$(dependencies_files): dependencies.m4 ../config.status
|
||||
define=`echo $@ | $(SED) 's/dependencies.//;y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`; \
|
||||
m4 -D$$define=1 -DGTK_VERSION=$(GTK_VERSION) $< > $@-t
|
||||
mv $@-t $@
|
||||
|
||||
# Support files needed by the virt-p2v-make-* scripts.
|
||||
virtp2vdatadir = $(datadir)/virt-p2v
|
||||
|
||||
virtp2vdata_DATA = \
|
||||
$(dependencies_files) \
|
||||
issue \
|
||||
kiwi-config.sh \
|
||||
kiwi-config.xml.in \
|
||||
launch-virt-p2v \
|
||||
p2v.ks.in \
|
||||
p2v.service
|
||||
|
||||
# Manual pages and HTML files for the website.
|
||||
man_MANS = \
|
||||
virt-p2v.1 \
|
||||
virt-p2v-make-disk.1 \
|
||||
virt-p2v-make-kickstart.1 \
|
||||
virt-p2v-make-kiwi.1
|
||||
|
||||
noinst_DATA = \
|
||||
$(top_builddir)/website/virt-p2v.1.html \
|
||||
$(top_builddir)/website/virt-p2v-make-disk.1.html \
|
||||
$(top_builddir)/website/virt-p2v-make-kickstart.1.html \
|
||||
$(top_builddir)/website/virt-p2v-make-kiwi.1.html
|
||||
|
||||
virt-p2v.1 $(top_builddir)/website/virt-p2v.1.html: stamp-virt-p2v.pod
|
||||
|
||||
stamp-virt-p2v.pod: virt-p2v.pod virt-p2v-kernel-config.pod
|
||||
$(PODWRAPPER) \
|
||||
--man virt-p2v.1 \
|
||||
--html $(top_builddir)/website/virt-p2v.1.html \
|
||||
--insert virt-p2v-kernel-config.pod:__KERNEL_CONFIG__ \
|
||||
--license GPLv2+ \
|
||||
--warning safe \
|
||||
$<
|
||||
touch $@
|
||||
|
||||
virt-p2v-make-disk.1 $(top_builddir)/website/virt-p2v-make-disk.1.html: stamp-virt-p2v-make-disk.pod
|
||||
|
||||
stamp-virt-p2v-make-disk.pod: virt-p2v-make-disk.pod
|
||||
$(PODWRAPPER) \
|
||||
--man virt-p2v-make-disk.1 \
|
||||
--html $(top_builddir)/website/virt-p2v-make-disk.1.html \
|
||||
--license GPLv2+ \
|
||||
--warning safe \
|
||||
$<
|
||||
touch $@
|
||||
|
||||
virt-p2v-make-kickstart.1 $(top_builddir)/website/virt-p2v-make-kickstart.1.html: stamp-virt-p2v-make-kickstart.pod
|
||||
|
||||
stamp-virt-p2v-make-kickstart.pod: virt-p2v-make-kickstart.pod
|
||||
$(PODWRAPPER) \
|
||||
--man virt-p2v-make-kickstart.1 \
|
||||
--html $(top_builddir)/website/virt-p2v-make-kickstart.1.html \
|
||||
--license GPLv2+ \
|
||||
--warning safe \
|
||||
$<
|
||||
touch $@
|
||||
|
||||
virt-p2v-make-kiwi.1 $(top_builddir)/website/virt-p2v-make-kiwi.1.html: stamp-virt-p2v-make-kiwi.pod
|
||||
|
||||
stamp-virt-p2v-make-kiwi.pod: virt-p2v-make-kiwi.pod
|
||||
$(PODWRAPPER) \
|
||||
--man virt-p2v-make-kiwi.1 \
|
||||
--html $(top_builddir)/website/virt-p2v-make-kiwi.1.html \
|
||||
--license GPLv2+ \
|
||||
--warning safe \
|
||||
$<
|
||||
touch $@
|
||||
|
||||
# Run virt-p2v locally either directly or in a VM.
|
||||
# See guestfs-hacking(1) section "Running virt-p2v"
|
||||
|
||||
PHYSICAL_MACHINE = $(abs_builddir)/fedora.img
|
||||
BLANK_DISK = blank-part.img
|
||||
|
||||
check_DATA = \
|
||||
$(PHYSICAL_MACHINE) \
|
||||
$(BLANK_DISK)
|
||||
|
||||
run-virt-p2v-directly: $(PHYSICAL_MACHINE)
|
||||
$(top_builddir)/run virt-p2v --test-disk=$(PHYSICAL_MACHINE)
|
||||
|
||||
run-virt-p2v-in-a-vm: virt-p2v.img $(PHYSICAL_MACHINE)
|
||||
$(QEMU) \
|
||||
-M pc,accel=kvm:tcg \
|
||||
-cpu host \
|
||||
-m 1024 \
|
||||
-drive id=hd0,file=$(PHYSICAL_MACHINE),format=raw,if=ide \
|
||||
-device piix3-usb-uhci \
|
||||
-drive id=usb0,file=$<,format=raw,snapshot=on,if=none \
|
||||
-device usb-storage,bootindex=1,drive=usb0 \
|
||||
-boot menu=on \
|
||||
-netdev user,id=net0,net=169.254.0.0/16 \
|
||||
-device virtio-net-pci,netdev=net0 \
|
||||
-netdev user,id=net1 \
|
||||
-device rtl8139,netdev=net1 \
|
||||
-netdev user,id=net2 \
|
||||
-device e1000,netdev=net2 \
|
||||
$(QEMU_OPTIONS) \
|
||||
&
|
||||
|
||||
run-virt-p2v-non-gui-conversion: stamp-test-virt-p2v-pxe-data-files
|
||||
SLOW=1 $(top_builddir)/run ./test-virt-p2v-pxe.sh
|
||||
|
||||
$(PHYSICAL_MACHINE):
|
||||
$(top_builddir)/run virt-builder --format raw -o $@ fedora-30
|
||||
|
||||
$(BLANK_DISK):
|
||||
$(top_builddir)/run guestfish -N $@=part exit
|
||||
|
||||
virt-p2v.img: \
|
||||
dependencies.m4 \
|
||||
issue \
|
||||
launch-virt-p2v \
|
||||
p2v.service \
|
||||
virt-p2v \
|
||||
virt-p2v-make-disk
|
||||
$(top_builddir)/run virt-p2v-make-disk -o $@
|
||||
|
||||
# Tests.
|
||||
|
||||
TESTS_ENVIRONMENT = $(top_builddir)/run --test
|
||||
|
||||
TESTS = \
|
||||
test-virt-p2v-cmdline.sh \
|
||||
test-virt-p2v-docs.sh
|
||||
|
||||
APPLIANCE_TESTS = \
|
||||
test-virt-p2v.sh \
|
||||
test-virt-p2v-nbdkit.sh
|
||||
|
||||
if ENABLE_APPLIANCE
|
||||
TESTS += \
|
||||
$(APPLIANCE_TESTS) \
|
||||
$(SLOW_TESTS)
|
||||
endif ENABLE_APPLIANCE
|
||||
|
||||
check-valgrind:
|
||||
make VG="@VG@" check
|
||||
|
||||
SLOW_TESTS = \
|
||||
test-virt-p2v-pxe.sh
|
||||
|
||||
check-slow: stamp-test-virt-p2v-pxe-data-files
|
||||
$(MAKE) check TESTS="$(SLOW_TESTS)" SLOW=1
|
||||
|
||||
stamp-test-virt-p2v-pxe-data-files: \
|
||||
test-virt-p2v-pxe.authorized_keys \
|
||||
test-virt-p2v-pxe.img \
|
||||
test-virt-p2v-pxe.vmlinuz test-virt-p2v-pxe.initramfs \
|
||||
test-virt-p2v-pxe.sshd_config \
|
||||
test-virt-p2v-pxe.ssh_host_rsa_key \
|
||||
test-virt-p2v-pxe.ssh_host_rsa_key.pub \
|
||||
test-virt-p2v-pxe.id_rsa test-virt-p2v-pxe.id_rsa.pub
|
||||
touch $@
|
||||
|
||||
test-virt-p2v-pxe.img: \
|
||||
dependencies.m4 \
|
||||
issue \
|
||||
launch-virt-p2v \
|
||||
p2v.service \
|
||||
test-virt-p2v-pxe.id_rsa \
|
||||
virt-p2v \
|
||||
virt-p2v-make-disk
|
||||
$(top_builddir)/run virt-p2v-make-disk \
|
||||
--inject-ssh-identity=test-virt-p2v-pxe.id_rsa \
|
||||
-o $@-t
|
||||
mv $@-t $@
|
||||
|
||||
test-virt-p2v-pxe.vmlinuz test-virt-p2v-pxe.initramfs: stamp-test-virt-p2v-pxe-kernel
|
||||
|
||||
stamp-test-virt-p2v-pxe-kernel: test-virt-p2v-pxe.img
|
||||
rm -f $@ vmlinuz initramfs test-virt-p2v-pxe.vmlinuz test-virt-p2v-pxe.initramfs
|
||||
$(top_builddir)/run virt-get-kernel --unversioned-names -a $<
|
||||
mv vmlinuz test-virt-p2v-pxe.vmlinuz
|
||||
mv initramfs test-virt-p2v-pxe.initramfs
|
||||
touch $@
|
||||
|
||||
test-virt-p2v-pxe.sshd_config: test-virt-p2v-pxe.sshd_config.in
|
||||
rm -f $@ $@-t
|
||||
@AWK@ \
|
||||
-v "abs_builddir=$(abs_builddir)" \
|
||||
'{ \
|
||||
gsub (/__RANDOM_PORT__/, 10000 + int (1000 * rand())); \
|
||||
gsub (/__abs_builddir__/, abs_builddir); \
|
||||
print; \
|
||||
}' < $< > $@-t
|
||||
chmod 0444 $@-t
|
||||
mv $@-t $@
|
||||
|
||||
test-virt-p2v-pxe.authorized_keys: test-virt-p2v-pxe.id_rsa.pub $(top_builddir)/run
|
||||
rm -f $@ $@-t
|
||||
$(top_builddir)/run sh -c 'echo -n environment=\"PATH=$$PATH\",environment=\"LD_LIBRARY_PATH=$(abs_top_builddir)/lib/.libs\",environment=\"LIBGUESTFS_PATH=$(abs_top_builddir)/appliance\",environment=\"LIBGUESTFS_CACHEDIR=$(abs_top_builddir)/tmp\"\ ' > $@-t
|
||||
cat $< >> $@-t
|
||||
mv $@-t $@
|
||||
|
||||
test-virt-p2v-pxe.ssh_host_rsa_key test-virt-p2v-pxe.ssh_host_rsa_key.pub: stamp-test-virt-p2v-pxe-hostkey
|
||||
|
||||
stamp-test-virt-p2v-pxe-hostkey:
|
||||
rm -f test-virt-p2v-pxe.ssh_host_rsa_key
|
||||
rm -f test-virt-p2v-pxe.ssh_host_rsa_key.pub
|
||||
ssh-keygen -t rsa -f test-virt-p2v-pxe.ssh_host_rsa_key -N ''
|
||||
touch $@
|
||||
|
||||
test-virt-p2v-pxe.id_rsa test-virt-p2v-pxe.id_rsa.pub: stamp-test-virt-p2v-pxe-userkey
|
||||
|
||||
stamp-test-virt-p2v-pxe-userkey:
|
||||
rm -f test-virt-p2v-pxe.id_rsa
|
||||
rm -f test-virt-p2v-pxe.id_rsa.pub
|
||||
ssh-keygen -t rsa -f test-virt-p2v-pxe.id_rsa -N ''
|
||||
touch $@
|
||||
@@ -1,196 +0,0 @@
|
||||
#!/bin/bash -
|
||||
# Auxiliary script for building virt-p2v ISO.
|
||||
# Copyright (C) 2017 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.
|
||||
|
||||
# See build-p2v-iso.sh
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
# Make sure we're in the virtual environment, and refuse to run otherwise.
|
||||
if [ ! -f /var/tmp/livecd ]; then
|
||||
echo "$0: do not run this script directly"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If the script exits for any reason (including success) reboot. This
|
||||
# in fact powers off the virtual machine because we are using
|
||||
# qemu -no-reboot.
|
||||
trap reboot INT QUIT TERM EXIT ERR
|
||||
|
||||
cd /var/tmp
|
||||
|
||||
osversion=`cat osversion`
|
||||
livecd=`cat livecd`
|
||||
source ./proxy
|
||||
prefix=`rpm --eval '%_prefix'`
|
||||
libdir=`rpm --eval '%_libdir'`
|
||||
sysconfdir=`rpm --eval '%_sysconfdir'`
|
||||
|
||||
# Build virt-p2v from libguestfs sources.
|
||||
# We have to start from a tarball because at least RHEL 5 autotools
|
||||
# isn't sufficiently new to run autoreconf.
|
||||
zcat libguestfs.tar.gz | tar xf -
|
||||
pushd libguestfs-*
|
||||
|
||||
# Various hacks for different versions of RHEL.
|
||||
case $osversion in
|
||||
rhel-5.*|centos-5.*)
|
||||
# This just forces configure to ignore these missing dependencies.
|
||||
export LIBTINFO_CFLAGS=-D_GNU_SOURCE
|
||||
export LIBTINFO_LIBS=-lncurses
|
||||
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
|
||||
# Apply some RHEL 5 only patches.
|
||||
patch -p1 < ../patches/0001-RHEL-5-ONLY-DISABLE-AUTOMATIC-REMOTE-PORT-ALLOCATION.patch
|
||||
patch -p1 < ../patches/0002-RHEL-5-ONLY-QEMU-NBD-1.4-HAS-NO-f-OPTION.patch
|
||||
;;
|
||||
rhel-6.*|centos-6.*)
|
||||
# This just forces configure to ignore these missing dependencies.
|
||||
export LIBTINFO_CFLAGS=-D_GNU_SOURCE
|
||||
export LIBTINFO_LIBS=-lncurses
|
||||
export JANSSON_CFLAGS=-D_GNU_SOURCE
|
||||
export JANSSON_LIBS=-ljansson
|
||||
;;
|
||||
esac
|
||||
|
||||
export vmchannel_test=no
|
||||
./configure \
|
||||
--prefix $prefix \
|
||||
--libdir $libdir \
|
||||
--sysconfdir $sysconfdir \
|
||||
--disable-static \
|
||||
--disable-appliance \
|
||||
--disable-daemon \
|
||||
--disable-lua \
|
||||
--disable-ocaml \
|
||||
--disable-perl \
|
||||
--disable-php \
|
||||
--disable-python \
|
||||
--disable-ruby \
|
||||
--with-qemu=no
|
||||
# We only need to build a handful of directories to get virt-p2v.
|
||||
make -C generator
|
||||
make -C gnulib/lib
|
||||
make -C common/utils
|
||||
make -C common/miniexpect
|
||||
make -C p2v virt-p2v virt-p2v.xz dependencies.redhat
|
||||
make run
|
||||
|
||||
# Check virt-p2v was built and runs.
|
||||
./run ./p2v/virt-p2v --version
|
||||
./run ./p2v/virt-p2v-make-kickstart --version
|
||||
|
||||
# Create the kickstart file.
|
||||
if [ "x$http_proxy" != "x" ]; then proxy="--proxy=$http_proxy"; fi
|
||||
./run ./p2v/virt-p2v-make-kickstart -o /var/tmp/p2v.ks $osversion $proxy
|
||||
|
||||
popd
|
||||
|
||||
# More hacks for different versions of RHEL.
|
||||
case $osversion in
|
||||
rhel-5.*|centos-5.*)
|
||||
# RHEL 5 livecd-tools is broken with syslinux, this fixes it:
|
||||
sed -i -e 's,/usr/lib/syslinux/,/usr/share/syslinux/,g'\
|
||||
/usr/lib/python2.4/site-packages/imgcreate/live.py
|
||||
# livecd-tools cannot parse certain aspects of the kickstart:
|
||||
sed -i \
|
||||
-e 's/--plaintext//g' \
|
||||
-e 's/^firewall.*//g' \
|
||||
-e 's/^%end.*//g' \
|
||||
p2v.ks
|
||||
# Remove some packages which don't exist on RHEL 5:
|
||||
sed -i \
|
||||
-e 's,^dracut-live.*,,g' \
|
||||
-e 's,^dejavu-.*,,g' \
|
||||
-e 's,^mesa-dri-drivers.*,,g' \
|
||||
-e 's,^network-manager-applet.*,,g' \
|
||||
-e 's,^nm-connection-editor.*,,g' \
|
||||
-e 's,^/usr/bin/qemu-nbd.*,,g' \
|
||||
-e '/^net-tools/a syslinux' \
|
||||
p2v.ks
|
||||
# Remove systemctl lines, doesn't exist on RHEL 5.
|
||||
sed -i \
|
||||
-e 's/^\(systemctl.*\)/#\1/g' \
|
||||
p2v.ks
|
||||
;;
|
||||
rhel-6.*|centos-6.*)
|
||||
# Remove some packages which don't exist on RHEL 6:
|
||||
sed -i \
|
||||
-e 's,^dracut-live.*,,g' \
|
||||
-e 's,^firewalld.*,,g' \
|
||||
-e 's,^network-manager-applet.*,,g' \
|
||||
-e 's,^nm-connection-editor.*,,g' \
|
||||
-e 's,^/usr/bin/qemu-nbd.*,,g' \
|
||||
p2v.ks
|
||||
# Remove systemctl lines, doesn't exist on RHEL 5.
|
||||
sed -i \
|
||||
-e 's/^\(systemctl.*\)/#\1/g' \
|
||||
p2v.ks
|
||||
;;
|
||||
esac
|
||||
|
||||
# Build nbdkit
|
||||
zcat nbdkit.tar.gz | tar xf -
|
||||
pushd nbdkit-*
|
||||
./configure \
|
||||
CFLAGS="-D_GNU_SOURCE" \
|
||||
--prefix $prefix \
|
||||
--libdir $libdir \
|
||||
--sysconfdir $sysconfdir \
|
||||
--without-liblzma
|
||||
make
|
||||
cp src/nbdkit ..
|
||||
cp plugins/file/.libs/nbdkit-file-plugin.so ..
|
||||
popd
|
||||
gzip -c nbdkit > nbdkit.gz
|
||||
gzip -c nbdkit-file-plugin.so > nbdkit-file-plugin.so.gz
|
||||
base64 nbdkit.gz > nbdkit.gz.b64
|
||||
base64 nbdkit-file-plugin.so.gz > nbdkit-file-plugin.so.gz.b64
|
||||
|
||||
# Add nbdkit binaries to the kickstart.
|
||||
echo > fragment.ks
|
||||
echo '#' `md5sum nbdkit` >> fragment.ks
|
||||
echo 'base64 -d -i <<EOF | gzip -cd > /usr/bin/nbdkit' >> fragment.ks
|
||||
cat nbdkit.gz.b64 >> fragment.ks
|
||||
echo >> fragment.ks
|
||||
echo EOF >> fragment.ks
|
||||
echo 'chmod 0755 /usr/bin/nbdkit' >> fragment.ks
|
||||
echo >> fragment.ks
|
||||
|
||||
echo '#' `md5sum nbdkit-file-plugin.so` >> fragment.ks
|
||||
echo 'mkdir -p' $libdir/nbdkit/plugins >> fragment.ks
|
||||
echo 'base64 -d -i <<EOF | gzip -cd >' $libdir/nbdkit/plugins/nbdkit-file-plugin.so >> fragment.ks
|
||||
cat nbdkit-file-plugin.so.gz.b64 >> fragment.ks
|
||||
echo >> fragment.ks
|
||||
echo EOF >> fragment.ks
|
||||
echo 'chmod 0755' $libdir/nbdkit/plugins/nbdkit-file-plugin.so >> fragment.ks
|
||||
echo >> fragment.ks
|
||||
|
||||
sed -i -e '/^chmod.*\/usr\/bin\/virt-p2v$/ r fragment.ks' p2v.ks
|
||||
|
||||
# Run livecd-creator to make the live CD. The strange redirect works
|
||||
# around a bug in RHEL 5's livecd-tools: "/sbin/mksquashfs: invalid
|
||||
# option" is printed if the output is redirected to a file
|
||||
# (https://bugs.centos.org/bug_view_page.php?bug_id=3738)
|
||||
livecd-creator -c p2v.ks > `tty` 2>&1
|
||||
|
||||
# Move the live CD to the final filename.
|
||||
mv livecd-*.iso $livecd
|
||||
@@ -1,155 +0,0 @@
|
||||
#!/bin/bash -
|
||||
# Build virt-p2v ISO for RHEL 5/6/7.
|
||||
# Copyright (C) 2017 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.
|
||||
|
||||
# This script is used to build the virt-p2v ISO on RHEL 5/6/7,
|
||||
# for 32 bit (i686) and 64 bit (x86-64).
|
||||
#
|
||||
# This script is *not* used to build the official RHEL 7 virt-p2v ISO
|
||||
# for Red Hat customers. However it is used to build alternate ISOs
|
||||
# which can optionally be used by customers who need older RHEL
|
||||
# (eg. for proprietary FakeRAID drivers), or have 32 bit physical
|
||||
# machines that they wish to virtualize.
|
||||
#
|
||||
# The virt-p2v ISOs built by this script are hosted at:
|
||||
# http://oirase.annexia.org/virt-p2v/
|
||||
|
||||
set -e
|
||||
|
||||
usage ()
|
||||
{
|
||||
echo ' libguestfs and nbdkit tarballs'
|
||||
echo ' (http URLs may also be used here)'
|
||||
echo ' |'
|
||||
echo './build-p2v-iso.sh file:///path/to/libguestfs-1.XX.YY.tar.gz \'
|
||||
echo ' file:///path/to/nbdkit-1.XX.YY.tar.gz \'
|
||||
echo ' rhel-5.11 i686'
|
||||
echo ' | |'
|
||||
echo ' | `--- architecture (i686 or x86_64)'
|
||||
echo ' `---- version of RHEL (5.x or 6.x tested)'
|
||||
echo
|
||||
echo 'Note this downloads the libguestfs tarball from upstream, it'
|
||||
echo 'does not use libguestfs from the current directory.'
|
||||
echo
|
||||
echo 'Minimum versions of: libguestfs = 1.35.22'
|
||||
echo ' nbdkit = 1.1.13'
|
||||
echo
|
||||
echo 'You should run the script on a Fedora (or recent Linux) host.'
|
||||
echo 'It uses virt-builder to create the RHEL environment'
|
||||
exit 0
|
||||
}
|
||||
|
||||
if [ $# -ne 4 ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
tmpdir="$(mktemp -d)"
|
||||
cleanup ()
|
||||
{
|
||||
rm -rf "$tmpdir"
|
||||
}
|
||||
trap cleanup INT QUIT TERM EXIT ERR
|
||||
|
||||
libguestfs_tarball=$1
|
||||
nbdkit_tarball=$2
|
||||
osversion=$3
|
||||
arch=$4
|
||||
|
||||
# Get the path to the auxiliary script.
|
||||
d="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
if [ ! -d "$d/aux-scripts" ]; then
|
||||
echo "$0: error: cannot locate auxiliary scripts"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Build the list of packages needed for the build environment.
|
||||
pkgs=augeas-devel,bison,coreutils,cpio,file-devel,flex,gcc,gperf,gtk2-devel,libxml2-devel,livecd-tools,mkisofs,ncurses-devel,patch,perl-Pod-Man,perl-Pod-Simple,pcre-devel,/usr/bin/pod2text,syslinux,syslinux-extlinux,xz,xz-devel
|
||||
|
||||
for f in `cat $d/../../p2v/dependencies.redhat`; do
|
||||
pkgs="$pkgs,$f"
|
||||
done
|
||||
|
||||
# Various hacks for different versions of RHEL.
|
||||
if=virtio
|
||||
netdev=virtio-net-pci
|
||||
declare -a epel
|
||||
case $osversion in
|
||||
rhel-5.*|centos-5.*)
|
||||
if=ide
|
||||
netdev=rtl8139
|
||||
# RHEL 5 yum cannot download a package.
|
||||
curl -o $tmpdir/epel-release.rpm https://dl.fedoraproject.org/pub/epel/epel-release-latest-5.noarch.rpm
|
||||
epel[0]="--upload"
|
||||
epel[1]="$tmpdir/epel-release.rpm:/var/tmp"
|
||||
# RHEL 5 i686 template has a broken RPM DB, so rebuild it.
|
||||
epel[2]="--run-command"
|
||||
epel[3]="rm -f /var/lib/rpm/__db*; rpm -vv --rebuilddb"
|
||||
epel[4]="--run-command"
|
||||
epel[5]="yum install -y --nogpgcheck /var/tmp/epel-release.rpm"
|
||||
;;
|
||||
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
|
||||
|
||||
# Download libguestfs and nbdkit sources.
|
||||
curl -o $tmpdir/libguestfs.tar.gz $libguestfs_tarball
|
||||
curl -o $tmpdir/nbdkit.tar.gz $nbdkit_tarball
|
||||
|
||||
# Write a proxy file for the guest environment.
|
||||
echo "export http_proxy=$http_proxy" >> $tmpdir/proxy
|
||||
echo "export https_proxy=$https_proxy" >> $tmpdir/proxy
|
||||
echo "export ftp_proxy=$ftp_proxy" >> $tmpdir/proxy
|
||||
|
||||
# Build the temporary guest RHEL environment.
|
||||
disk=$tmpdir/tmp-$osversion.img
|
||||
livecd=virt-p2v-livecd-$osversion-$arch-`date +"%Y%m%d%H%M"`.iso
|
||||
virt-builder $osversion --arch $arch \
|
||||
--size 20G --output $disk \
|
||||
"${epel[@]}" \
|
||||
--install "$pkgs" \
|
||||
--upload $tmpdir/libguestfs.tar.gz:/var/tmp \
|
||||
--upload $tmpdir/nbdkit.tar.gz:/var/tmp \
|
||||
--copy-in $d/patches:/var/tmp \
|
||||
--write /var/tmp/osversion:$osversion \
|
||||
--write /var/tmp/livecd:$livecd \
|
||||
--upload $tmpdir/proxy:/var/tmp/proxy \
|
||||
--firstboot $d/aux-scripts/do-build.sh \
|
||||
--selinux-relabel
|
||||
|
||||
# Run the guest.
|
||||
qemu-system-x86_64 -no-user-config -nodefaults -nographic \
|
||||
-no-reboot \
|
||||
-machine accel=kvm:tcg \
|
||||
-cpu host \
|
||||
-m 4096 \
|
||||
-drive file=$disk,format=raw,if=$if \
|
||||
-netdev user,id=usernet,net=169.254.0.0/16 \
|
||||
-device $netdev,netdev=usernet \
|
||||
-serial stdio
|
||||
|
||||
# Did we get any output from the auxiliary script?
|
||||
# (This command will fail if not)
|
||||
guestfish --ro -a $disk -i download /var/tmp/$livecd $livecd
|
||||
ls -lh $livecd
|
||||
@@ -1,54 +0,0 @@
|
||||
From 28dd464c8e78f241622d142671a61a75bf5d758e Mon Sep 17 00:00:00 2001
|
||||
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||
Date: Sat, 21 Jan 2017 05:30:40 -0500
|
||||
Subject: [PATCH 1/2] RHEL 5 ONLY DISABLE AUTOMATIC REMOTE PORT ALLOCATION
|
||||
|
||||
---
|
||||
p2v/ssh.c | 15 ++++++++++++++-
|
||||
1 file changed, 14 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/p2v/ssh.c b/p2v/ssh.c
|
||||
index 8beaf74..919f2df 100644
|
||||
--- a/p2v/ssh.c
|
||||
+++ b/p2v/ssh.c
|
||||
@@ -1044,16 +1044,28 @@ open_data_connection (struct config *config,
|
||||
"-N",
|
||||
NULL
|
||||
};
|
||||
+#if 0
|
||||
CLEANUP_FREE char *port_str = NULL;
|
||||
const int ovecsize = 12;
|
||||
int ovector[ovecsize];
|
||||
+#endif
|
||||
|
||||
- snprintf (remote_arg, sizeof remote_arg, "0:%s:%d", local_ipaddr, local_port);
|
||||
+ /* RHEL 5 hack: ssh does not print the "Allocated port ..." string,
|
||||
+ * so we cannot find the remotely allocated port. Instead just
|
||||
+ * assign a random port and hope for the best.
|
||||
+ */
|
||||
+ static int next_remote_port = 58123;
|
||||
+
|
||||
+ snprintf (remote_arg, sizeof remote_arg, "%d:%s:%d",
|
||||
+ next_remote_port, local_ipaddr, local_port);
|
||||
+ *remote_port = next_remote_port;
|
||||
+ next_remote_port++;
|
||||
|
||||
h = start_ssh (0, config, (char **) extra_args, 0);
|
||||
if (h == NULL)
|
||||
return NULL;
|
||||
|
||||
+#if 0
|
||||
switch (mexp_expect (h,
|
||||
(mexp_regexp[]) {
|
||||
{ 100, .re = portfwd_re },
|
||||
@@ -1094,6 +1106,7 @@ open_data_connection (struct config *config,
|
||||
mexp_close (h);
|
||||
return NULL;
|
||||
}
|
||||
+#endif
|
||||
|
||||
return h;
|
||||
}
|
||||
--
|
||||
1.8.2.3
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
From 3ccd25c981431426038d7952f5b0b86118d92c23 Mon Sep 17 00:00:00 2001
|
||||
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||
Date: Sat, 21 Jan 2017 05:57:17 -0500
|
||||
Subject: [PATCH 2/2] RHEL 5 ONLY QEMU-NBD 1.4 HAS NO -f OPTION
|
||||
|
||||
---
|
||||
p2v/nbd.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/p2v/nbd.c b/p2v/nbd.c
|
||||
index b1caf2f..2232b08 100644
|
||||
--- a/p2v/nbd.c
|
||||
+++ b/p2v/nbd.c
|
||||
@@ -409,7 +409,7 @@ start_qemu_nbd (const char *device,
|
||||
"-r", /* readonly (vital!) */
|
||||
"-p", port_str, /* listening port */
|
||||
"-t", /* persistent */
|
||||
- "-f", "raw", /* force raw format */
|
||||
+ //"-f", "raw", /* force raw format */
|
||||
"-b", ipaddr, /* listen only on loopback interface */
|
||||
"--cache=unsafe", /* use unsafe caching for speed */
|
||||
device, /* a device like /dev/sda */
|
||||
@@ -424,7 +424,7 @@ start_qemu_nbd (const char *device,
|
||||
"qemu-nbd",
|
||||
"-r", /* readonly (vital!) */
|
||||
"-t", /* persistent */
|
||||
- "-f", "raw", /* force raw format */
|
||||
+ //"-f", "raw", /* force raw format */
|
||||
"--cache=unsafe", /* use unsafe caching for speed */
|
||||
device, /* a device like /dev/sda */
|
||||
NULL);
|
||||
--
|
||||
1.8.2.3
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
#!/bin/bash -
|
||||
# Test virt-p2v ISO for RHEL 5/6/7.
|
||||
# Copyright (C) 2017 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.
|
||||
|
||||
# Once you have built a virt-p2v ISO (see build-p2v-iso.sh), you
|
||||
# can interactively test it using this script.
|
||||
|
||||
set -e
|
||||
|
||||
usage ()
|
||||
{
|
||||
echo './test-p2v-iso.sh virt-p2v-livecd-....iso'
|
||||
exit 0
|
||||
}
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
tmpdir="$(mktemp -d)"
|
||||
cleanup ()
|
||||
{
|
||||
rm -rf "$tmpdir"
|
||||
}
|
||||
trap cleanup INT QUIT TERM EXIT ERR
|
||||
|
||||
iso=$1
|
||||
if [ ! -f "$iso" ]; then
|
||||
echo "$iso: file not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Build a temporary guest to test.
|
||||
disk=$tmpdir/guest.img
|
||||
virt-builder rhel-6.8 --output $disk
|
||||
|
||||
# Boot the guest as if running with virt-p2v ISO in the CD drive.
|
||||
qemu-system-x86_64 -no-user-config -nodefaults \
|
||||
-no-reboot \
|
||||
-machine accel=kvm:tcg \
|
||||
-cpu host \
|
||||
-m 4096 \
|
||||
-display gtk \
|
||||
-vga std \
|
||||
-drive file=$disk,format=raw,if=ide \
|
||||
-cdrom $iso \
|
||||
-netdev user,id=usernet,net=169.254.0.0/16 \
|
||||
-device rtl8139,netdev=usernet \
|
||||
-boot d
|
||||
668
p2v/conversion.c
668
p2v/conversion.c
@@ -1,668 +0,0 @@
|
||||
/* virt-p2v
|
||||
* Copyright (C) 2009-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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file manages the p2v conversion.
|
||||
*
|
||||
* The conversion is actually done by L<virt-v2v(1)> running on the
|
||||
* remote conversion server. This file manages running the remote
|
||||
* command and provides callbacks for displaying the output.
|
||||
*
|
||||
* When virt-p2v operates in GUI mode, this code runs in a separate
|
||||
* thread. When virt-p2v operates in kernel mode, this runs
|
||||
* synchronously in the main thread.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <locale.h>
|
||||
#include <libintl.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "ignore-value.h"
|
||||
#include "getprogname.h"
|
||||
|
||||
#include "miniexpect.h"
|
||||
#include "p2v.h"
|
||||
|
||||
static void cleanup_data_conns (struct data_conn *data_conns, size_t nr);
|
||||
static void generate_name (struct config *, const char *filename);
|
||||
static void generate_wrapper_script (struct config *, const char *remote_dir, const char *filename);
|
||||
static void generate_system_data (const char *dmesg_file, const char *lscpu_file, const char *lspci_file, const char *lsscsi_file, const char *lsusb_file);
|
||||
static void generate_p2v_version_file (const char *p2v_version_file);
|
||||
static void print_quoted (FILE *fp, const char *s);
|
||||
|
||||
static char *conversion_error;
|
||||
|
||||
static void set_conversion_error (const char *fs, ...)
|
||||
__attribute__((format(printf,1,2)));
|
||||
|
||||
static void
|
||||
set_conversion_error (const char *fs, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *msg;
|
||||
int len;
|
||||
|
||||
va_start (args, fs);
|
||||
len = vasprintf (&msg, fs, args);
|
||||
va_end (args);
|
||||
|
||||
if (len < 0)
|
||||
error (EXIT_FAILURE, errno,
|
||||
"vasprintf (original error format string: %s)", fs);
|
||||
|
||||
free (conversion_error);
|
||||
conversion_error = msg;
|
||||
}
|
||||
|
||||
const char *
|
||||
get_conversion_error (void)
|
||||
{
|
||||
return conversion_error;
|
||||
}
|
||||
|
||||
static pthread_mutex_t running_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int running = 0;
|
||||
static pthread_mutex_t cancel_requested_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int cancel_requested = 0;
|
||||
static mexp_h *control_h = NULL;
|
||||
|
||||
static int
|
||||
is_running (void)
|
||||
{
|
||||
int r;
|
||||
pthread_mutex_lock (&running_mutex);
|
||||
r = running;
|
||||
pthread_mutex_unlock (&running_mutex);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
set_running (int r)
|
||||
{
|
||||
pthread_mutex_lock (&running_mutex);
|
||||
running = r;
|
||||
pthread_mutex_unlock (&running_mutex);
|
||||
}
|
||||
|
||||
static int
|
||||
is_cancel_requested (void)
|
||||
{
|
||||
int r;
|
||||
pthread_mutex_lock (&cancel_requested_mutex);
|
||||
r = cancel_requested;
|
||||
pthread_mutex_unlock (&cancel_requested_mutex);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
set_cancel_requested (int r)
|
||||
{
|
||||
pthread_mutex_lock (&cancel_requested_mutex);
|
||||
cancel_requested = r;
|
||||
|
||||
/* Send ^C to the remote so that virt-v2v "knows" the connection has
|
||||
* been cancelled. mexp_send_interrupt is a single write(2) call.
|
||||
*/
|
||||
if (r && control_h)
|
||||
ignore_value (mexp_send_interrupt (control_h));
|
||||
|
||||
pthread_mutex_unlock (&cancel_requested_mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
set_control_h (mexp_h *new_h)
|
||||
{
|
||||
pthread_mutex_lock (&cancel_requested_mutex);
|
||||
control_h = new_h;
|
||||
pthread_mutex_unlock (&cancel_requested_mutex);
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wsuggest-attribute=noreturn"
|
||||
int
|
||||
start_conversion (struct config *config,
|
||||
void (*notify_ui) (int type, const char *data))
|
||||
{
|
||||
int ret = -1;
|
||||
int status;
|
||||
size_t i, len;
|
||||
const size_t nr_disks = guestfs_int_count_strings (config->disks);
|
||||
time_t now;
|
||||
struct tm tm;
|
||||
CLEANUP_FREE struct data_conn *data_conns = NULL;
|
||||
CLEANUP_FREE char *remote_dir = NULL;
|
||||
char tmpdir[] = "/tmp/p2v.XXXXXX";
|
||||
char name_file[] = "/tmp/p2v.XXXXXX/name";
|
||||
char physical_xml_file[] = "/tmp/p2v.XXXXXX/physical.xml";
|
||||
char wrapper_script[] = "/tmp/p2v.XXXXXX/virt-v2v-wrapper.sh";
|
||||
char dmesg_file[] = "/tmp/p2v.XXXXXX/dmesg";
|
||||
char lscpu_file[] = "/tmp/p2v.XXXXXX/lscpu";
|
||||
char lspci_file[] = "/tmp/p2v.XXXXXX/lspci";
|
||||
char lsscsi_file[] = "/tmp/p2v.XXXXXX/lsscsi";
|
||||
char lsusb_file[] = "/tmp/p2v.XXXXXX/lsusb";
|
||||
char p2v_version_file[] = "/tmp/p2v.XXXXXX/p2v-version";
|
||||
int inhibit_fd = -1;
|
||||
|
||||
#if DEBUG_STDERR
|
||||
print_config (config, stderr);
|
||||
fprintf (stderr, "\n");
|
||||
#endif
|
||||
|
||||
set_control_h (NULL);
|
||||
set_running (1);
|
||||
set_cancel_requested (0);
|
||||
|
||||
inhibit_fd = inhibit_power_saving ();
|
||||
#ifdef DEBUG_STDERR
|
||||
if (inhibit_fd == -1)
|
||||
fprintf (stderr, "warning: virt-p2v cannot inhibit power saving during conversion.\n");
|
||||
#endif
|
||||
|
||||
data_conns = malloc (sizeof (struct data_conn) * nr_disks);
|
||||
if (data_conns == NULL)
|
||||
error (EXIT_FAILURE, errno, "malloc");
|
||||
|
||||
for (i = 0; config->disks[i] != NULL; ++i) {
|
||||
data_conns[i].h = NULL;
|
||||
data_conns[i].nbd_pid = 0;
|
||||
data_conns[i].nbd_remote_port = -1;
|
||||
}
|
||||
|
||||
/* Start the data connections and NBD server processes, one per disk. */
|
||||
for (i = 0; config->disks[i] != NULL; ++i) {
|
||||
const char *nbd_local_ipaddr;
|
||||
int nbd_local_port;
|
||||
CLEANUP_FREE char *device = NULL;
|
||||
|
||||
if (config->disks[i][0] == '/') {
|
||||
device = strdup (config->disks[i]);
|
||||
if (!device) {
|
||||
perror ("strdup");
|
||||
cleanup_data_conns (data_conns, nr_disks);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else if (asprintf (&device, "/dev/%s", config->disks[i]) == -1) {
|
||||
perror ("asprintf");
|
||||
cleanup_data_conns (data_conns, nr_disks);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (notify_ui) {
|
||||
CLEANUP_FREE char *msg;
|
||||
if (asprintf (&msg,
|
||||
_("Starting local NBD server for %s ..."),
|
||||
config->disks[i]) == -1)
|
||||
error (EXIT_FAILURE, errno, "asprintf");
|
||||
notify_ui (NOTIFY_STATUS, msg);
|
||||
}
|
||||
|
||||
/* Start NBD server listening on the given port number. */
|
||||
data_conns[i].nbd_pid =
|
||||
start_nbd_server (&nbd_local_ipaddr, &nbd_local_port, device);
|
||||
if (data_conns[i].nbd_pid == 0) {
|
||||
set_conversion_error ("NBD server error: %s", get_nbd_error ());
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Wait for NBD server to start up and listen. */
|
||||
if (wait_for_nbd_server_to_start (nbd_local_ipaddr, nbd_local_port) == -1) {
|
||||
set_conversion_error ("NBD server error: %s", get_nbd_error ());
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (notify_ui) {
|
||||
CLEANUP_FREE char *msg;
|
||||
if (asprintf (&msg,
|
||||
_("Opening data connection for %s ..."),
|
||||
config->disks[i]) == -1)
|
||||
error (EXIT_FAILURE, errno, "asprintf");
|
||||
notify_ui (NOTIFY_STATUS, msg);
|
||||
}
|
||||
|
||||
/* Open the SSH data connection, with reverse port forwarding
|
||||
* back to the NBD server.
|
||||
*/
|
||||
data_conns[i].h = open_data_connection (config,
|
||||
nbd_local_ipaddr, nbd_local_port,
|
||||
&data_conns[i].nbd_remote_port);
|
||||
if (data_conns[i].h == NULL) {
|
||||
const char *err = get_ssh_error ();
|
||||
|
||||
set_conversion_error ("could not open data connection over SSH to the conversion server: %s", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if DEBUG_STDERR
|
||||
fprintf (stderr,
|
||||
"%s: data connection for %s: SSH remote port %d, local port %s:%d\n",
|
||||
getprogname (), device,
|
||||
data_conns[i].nbd_remote_port,
|
||||
nbd_local_ipaddr, nbd_local_port);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Create a remote directory name which will be used for libvirt
|
||||
* XML, log files and other stuff. We don't delete this directory
|
||||
* after the run because (a) it's useful for debugging and (b) it
|
||||
* only contains small files.
|
||||
*
|
||||
* NB: This path MUST NOT require shell quoting.
|
||||
*/
|
||||
time (&now);
|
||||
gmtime_r (&now, &tm);
|
||||
if (asprintf (&remote_dir,
|
||||
"/tmp/virt-p2v-%04d%02d%02d-XXXXXXXX",
|
||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday) == -1) {
|
||||
perror ("asprintf");
|
||||
cleanup_data_conns (data_conns, nr_disks);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
len = strlen (remote_dir);
|
||||
guestfs_int_random_string (&remote_dir[len-8], 8);
|
||||
if (notify_ui)
|
||||
notify_ui (NOTIFY_LOG_DIR, remote_dir);
|
||||
|
||||
/* Generate the local temporary directory. */
|
||||
if (mkdtemp (tmpdir) == NULL) {
|
||||
perror ("mkdtemp");
|
||||
cleanup_data_conns (data_conns, nr_disks);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
memcpy (name_file, tmpdir, strlen (tmpdir));
|
||||
memcpy (physical_xml_file, tmpdir, strlen (tmpdir));
|
||||
memcpy (wrapper_script, tmpdir, strlen (tmpdir));
|
||||
memcpy (dmesg_file, tmpdir, strlen (tmpdir));
|
||||
memcpy (lscpu_file, tmpdir, strlen (tmpdir));
|
||||
memcpy (lspci_file, tmpdir, strlen (tmpdir));
|
||||
memcpy (lsscsi_file, tmpdir, strlen (tmpdir));
|
||||
memcpy (lsusb_file, tmpdir, strlen (tmpdir));
|
||||
memcpy (p2v_version_file, tmpdir, strlen (tmpdir));
|
||||
|
||||
/* Generate the static files. */
|
||||
generate_name (config, name_file);
|
||||
generate_physical_xml (config, data_conns, physical_xml_file);
|
||||
generate_wrapper_script (config, remote_dir, wrapper_script);
|
||||
generate_system_data (dmesg_file,
|
||||
lscpu_file, lspci_file, lsscsi_file, lsusb_file);
|
||||
generate_p2v_version_file (p2v_version_file);
|
||||
|
||||
/* Open the control connection. This also creates remote_dir. */
|
||||
if (notify_ui)
|
||||
notify_ui (NOTIFY_STATUS, _("Setting up the control connection ..."));
|
||||
|
||||
set_control_h (start_remote_connection (config, remote_dir));
|
||||
if (control_h == NULL) {
|
||||
set_conversion_error ("could not open control connection over SSH to the conversion server: %s",
|
||||
get_ssh_error ());
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Copy the static files to the remote dir. */
|
||||
|
||||
/* These three files must not fail, so check for errors here. */
|
||||
if (scp_file (config, remote_dir,
|
||||
name_file, physical_xml_file, wrapper_script, NULL) == -1) {
|
||||
set_conversion_error ("scp: %s: %s",
|
||||
remote_dir, get_ssh_error ());
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* It's not essential that these files are copied, so ignore errors. */
|
||||
ignore_value (scp_file (config, remote_dir,
|
||||
dmesg_file, lscpu_file, lspci_file, lsscsi_file,
|
||||
lsusb_file, p2v_version_file, NULL));
|
||||
|
||||
/* Do the conversion. This runs until virt-v2v exits. */
|
||||
if (notify_ui)
|
||||
notify_ui (NOTIFY_STATUS, _("Doing conversion ..."));
|
||||
|
||||
if (mexp_printf (control_h,
|
||||
/* To simplify things in the wrapper script, it
|
||||
* writes virt-v2v's exit status to
|
||||
* /remote_dir/status, and here we read that and
|
||||
* exit the ssh shell with the same status.
|
||||
*/
|
||||
"%s/virt-v2v-wrapper.sh; "
|
||||
"exit $(< %s/status)\n",
|
||||
remote_dir, remote_dir) == -1) {
|
||||
set_conversion_error ("mexp_printf: virt-v2v: %m");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Read output from the virt-v2v process and echo it through the
|
||||
* notify function, until virt-v2v closes the connection.
|
||||
*/
|
||||
while (!is_cancel_requested ()) {
|
||||
char buf[257];
|
||||
ssize_t r;
|
||||
|
||||
r = read (mexp_get_fd (control_h), buf, sizeof buf - 1);
|
||||
if (r == -1) {
|
||||
/* See comment about this in miniexpect.c. */
|
||||
if (errno == EIO)
|
||||
break; /* EOF */
|
||||
set_conversion_error ("read: %m");
|
||||
goto out;
|
||||
}
|
||||
if (r == 0)
|
||||
break; /* EOF */
|
||||
buf[r] = '\0';
|
||||
if (notify_ui)
|
||||
notify_ui (NOTIFY_REMOTE_MESSAGE, buf);
|
||||
}
|
||||
|
||||
if (is_cancel_requested ()) {
|
||||
set_conversion_error ("cancelled by user");
|
||||
if (notify_ui)
|
||||
notify_ui (NOTIFY_STATUS, _("Conversion cancelled by user."));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (notify_ui)
|
||||
notify_ui (NOTIFY_STATUS, _("Control connection closed by remote."));
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
if (control_h) {
|
||||
mexp_h *h = control_h;
|
||||
set_control_h (NULL);
|
||||
status = mexp_close (h);
|
||||
|
||||
if (status == -1) {
|
||||
set_conversion_error ("mexp_close: %m");
|
||||
ret = -1;
|
||||
}
|
||||
else if (ret == 0 &&
|
||||
WIFEXITED (status) &&
|
||||
WEXITSTATUS (status) != 0) {
|
||||
set_conversion_error ("virt-v2v exited with status %d",
|
||||
WEXITSTATUS (status));
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
cleanup_data_conns (data_conns, nr_disks);
|
||||
|
||||
if (inhibit_fd >= 0)
|
||||
close (inhibit_fd);
|
||||
|
||||
set_running (0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
conversion_is_running (void)
|
||||
{
|
||||
return is_running ();
|
||||
}
|
||||
|
||||
void
|
||||
cancel_conversion (void)
|
||||
{
|
||||
set_cancel_requested (1);
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_data_conns (struct data_conn *data_conns, size_t nr)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < nr; ++i) {
|
||||
if (data_conns[i].h != NULL) {
|
||||
/* Because there is no SSH prompt (ssh -N), the only way to kill
|
||||
* these ssh connections is to send a signal. Just closing the
|
||||
* pipe doesn't do anything.
|
||||
*/
|
||||
kill (mexp_get_pid (data_conns[i].h), SIGHUP);
|
||||
mexp_close (data_conns[i].h);
|
||||
}
|
||||
|
||||
if (data_conns[i].nbd_pid > 0) {
|
||||
/* Kill NBD process and clean up. */
|
||||
kill (data_conns[i].nbd_pid, SIGTERM);
|
||||
waitpid (data_conns[i].nbd_pid, NULL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the guest name into C<filename>.
|
||||
*/
|
||||
static void
|
||||
generate_name (struct config *config, const char *filename)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen (filename, "w");
|
||||
if (fp == NULL)
|
||||
error (EXIT_FAILURE, errno, "fopen: %s", filename);
|
||||
fprintf (fp, "%s\n", config->guestname);
|
||||
fclose (fp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the virt-v2v wrapper script.
|
||||
*
|
||||
* This will be sent to the remote server, and is easier than trying
|
||||
* to "type" a long and complex single command line into the ssh
|
||||
* connection when we start the conversion.
|
||||
*/
|
||||
static void
|
||||
generate_wrapper_script (struct config *config, const char *remote_dir,
|
||||
const char *filename)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen (filename, "w");
|
||||
if (fp == NULL)
|
||||
error (EXIT_FAILURE, errno, "fopen: %s", filename);
|
||||
|
||||
fprintf (fp, "#!/bin/bash -\n");
|
||||
fprintf (fp, "\n");
|
||||
|
||||
fprintf (fp, "cd %s\n", remote_dir);
|
||||
fprintf (fp, "\n");
|
||||
|
||||
/* The virt-v2v command, as a shell function called "v2v". */
|
||||
fprintf (fp, "v2v ()\n");
|
||||
fprintf (fp, "{\n");
|
||||
if (config->auth.sudo)
|
||||
fprintf (fp, "sudo -n ");
|
||||
fprintf (fp, "virt-v2v -v -x");
|
||||
if (feature_colours_option)
|
||||
fprintf (fp, " --colours");
|
||||
fprintf (fp, " -i libvirtxml");
|
||||
|
||||
if (config->output.type) { /* -o */
|
||||
fprintf (fp, " -o ");
|
||||
print_quoted (fp, config->output.type);
|
||||
}
|
||||
|
||||
switch (config->output.allocation) { /* -oa */
|
||||
case OUTPUT_ALLOCATION_NONE:
|
||||
/* nothing */
|
||||
break;
|
||||
case OUTPUT_ALLOCATION_SPARSE:
|
||||
fprintf (fp, " -oa sparse");
|
||||
break;
|
||||
case OUTPUT_ALLOCATION_PREALLOCATED:
|
||||
fprintf (fp, " -oa preallocated");
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
if (config->output.format) { /* -of */
|
||||
fprintf (fp, " -of ");
|
||||
print_quoted (fp, config->output.format);
|
||||
}
|
||||
|
||||
if (config->output.storage) { /* -os */
|
||||
fprintf (fp, " -os ");
|
||||
print_quoted (fp, config->output.storage);
|
||||
}
|
||||
|
||||
fprintf (fp, " --root first");
|
||||
fprintf (fp, " physical.xml");
|
||||
fprintf (fp, " </dev/null"); /* no stdin */
|
||||
fprintf (fp, "\n");
|
||||
fprintf (fp,
|
||||
"# Save the exit code of virt-v2v into the 'status' file.\n");
|
||||
fprintf (fp, "echo $? > status\n");
|
||||
fprintf (fp, "}\n");
|
||||
fprintf (fp, "\n");
|
||||
|
||||
fprintf (fp,
|
||||
"# Write a pre-emptive error status, in case the virt-v2v\n"
|
||||
"# command doesn't get to run at all. This will be\n"
|
||||
"# overwritten with the true exit code when virt-v2v runs.\n");
|
||||
fprintf (fp, "echo 99 > status\n");
|
||||
fprintf (fp, "\n");
|
||||
|
||||
fprintf (fp, "log=virt-v2v-conversion-log.txt\n");
|
||||
fprintf (fp, "rm -f $log\n");
|
||||
fprintf (fp, "\n");
|
||||
|
||||
fprintf (fp,
|
||||
"# Log the environment where virt-v2v will run.\n");
|
||||
fprintf (fp, "printenv > environment\n");
|
||||
fprintf (fp, "\n");
|
||||
|
||||
fprintf (fp,
|
||||
"# Log the version of virt-v2v (for information only).\n");
|
||||
if (config->auth.sudo)
|
||||
fprintf (fp, "sudo -n ");
|
||||
fprintf (fp, "virt-v2v --version > v2v-version\n");
|
||||
fprintf (fp, "\n");
|
||||
|
||||
fprintf (fp,
|
||||
"# Run virt-v2v. Send stdout back to virt-p2v. Send stdout\n"
|
||||
"# and stderr (debugging info) to the log file.\n");
|
||||
fprintf (fp, "v2v 2>> $log | tee -a $log\n");
|
||||
fprintf (fp, "\n");
|
||||
|
||||
fprintf (fp,
|
||||
"# If virt-v2v failed then the error message (sent to stderr)\n"
|
||||
"# will not be seen in virt-p2v. Send the last few lines of\n"
|
||||
"# the log back to virt-p2v in this case.\n");
|
||||
fprintf (fp,
|
||||
"if [ \"$(< status)\" -ne 0 ]; then\n"
|
||||
" echo\n"
|
||||
" echo\n"
|
||||
" echo\n"
|
||||
" echo -ne '\\e[1;31m'\n"
|
||||
" echo '***' virt-v2v command failed '***'\n"
|
||||
" echo\n"
|
||||
" echo The full log is available on the conversion server in:\n"
|
||||
" echo ' ' %s/$log\n"
|
||||
" echo Only the last 50 lines are shown below.\n"
|
||||
" echo -ne '\\e[0m'\n"
|
||||
" echo\n"
|
||||
" echo\n"
|
||||
" echo\n"
|
||||
" tail -50 $log\n"
|
||||
"fi\n",
|
||||
remote_dir);
|
||||
|
||||
fprintf (fp, "\n");
|
||||
fprintf (fp, "# EOF\n");
|
||||
fclose (fp);
|
||||
|
||||
if (chmod (filename, 0755) == -1)
|
||||
error (EXIT_FAILURE, errno, "chmod: %s", filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a shell-quoted string on C<fp>.
|
||||
*/
|
||||
static void
|
||||
print_quoted (FILE *fp, const char *s)
|
||||
{
|
||||
fprintf (fp, "\"");
|
||||
while (*s) {
|
||||
if (*s == '$' || *s == '`' || *s == '\\' || *s == '"')
|
||||
fprintf (fp, "\\");
|
||||
fprintf (fp, "%c", *s);
|
||||
++s;
|
||||
}
|
||||
fprintf (fp, "\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect data about the system running virt-p2v such as the dmesg
|
||||
* output and lists of PCI devices. This is useful for diagnosis when
|
||||
* things go wrong.
|
||||
*
|
||||
* If any command fails, this is non-fatal.
|
||||
*/
|
||||
static void
|
||||
generate_system_data (const char *dmesg_file,
|
||||
const char *lscpu_file,
|
||||
const char *lspci_file,
|
||||
const char *lsscsi_file,
|
||||
const char *lsusb_file)
|
||||
{
|
||||
CLEANUP_FREE char *cmd = NULL;
|
||||
|
||||
if (asprintf (&cmd,
|
||||
"dmesg >%s 2>&1; "
|
||||
"lscpu >%s 2>&1; "
|
||||
"lspci -vvv >%s 2>&1; "
|
||||
"lsscsi -v >%s 2>&1; "
|
||||
"lsusb -v >%s 2>&1",
|
||||
dmesg_file, lscpu_file, lspci_file, lsscsi_file, lsusb_file)
|
||||
== -1)
|
||||
error (EXIT_FAILURE, errno, "asprintf");
|
||||
|
||||
ignore_value (system (cmd));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a file containing the version of virt-p2v.
|
||||
*
|
||||
* The version of virt-v2v is contained in the conversion log.
|
||||
*/
|
||||
static void
|
||||
generate_p2v_version_file (const char *p2v_version_file)
|
||||
{
|
||||
FILE *fp = fopen (p2v_version_file, "w");
|
||||
if (fp == NULL) {
|
||||
perror (p2v_version_file);
|
||||
return; /* non-fatal */
|
||||
}
|
||||
fprintf (fp, "%s %s\n",
|
||||
getprogname (), PACKAGE_VERSION_FULL);
|
||||
fclose (fp);
|
||||
}
|
||||
222
p2v/cpuid.c
222
p2v/cpuid.c
@@ -1,222 +0,0 @@
|
||||
/* virt-p2v
|
||||
* Copyright (C) 2009-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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Find CPU vendor, topology and some CPU flags.
|
||||
*
|
||||
* lscpu (from util-linux) provides CPU vendor, topology and flags.
|
||||
*
|
||||
* ACPI can be read by seeing if F</sys/firmware/acpi> exists.
|
||||
*
|
||||
* CPU model is essentially impossible to get without using libvirt,
|
||||
* but we cannot use libvirt for the reasons outlined in this message:
|
||||
* https://www.redhat.com/archives/libvirt-users/2017-March/msg00071.html
|
||||
*
|
||||
* Note that #vCPUs and amount of RAM is handled by F<main.c>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "c-ctype.h"
|
||||
#include "getprogname.h"
|
||||
#include "ignore-value.h"
|
||||
|
||||
#include "p2v.h"
|
||||
|
||||
static void
|
||||
free_cpu_config (struct cpu_config *cpu)
|
||||
{
|
||||
if (cpu->vendor)
|
||||
free (cpu->vendor);
|
||||
if (cpu->model)
|
||||
free (cpu->model);
|
||||
memset (cpu, 0, sizeof *cpu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the output of lscpu as a list of (key, value) pairs (as a
|
||||
* flattened list of strings).
|
||||
*/
|
||||
static char **
|
||||
get_lscpu (void)
|
||||
{
|
||||
const char *cmd;
|
||||
CLEANUP_PCLOSE FILE *fp = NULL;
|
||||
CLEANUP_FREE char *line = NULL;
|
||||
ssize_t len;
|
||||
size_t buflen = 0;
|
||||
char **ret = NULL;
|
||||
size_t ret_size = 0;
|
||||
|
||||
cmd = "lscpu";
|
||||
|
||||
fp = popen (cmd, "re");
|
||||
if (fp == NULL) {
|
||||
perror (cmd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = malloc (sizeof (char *));
|
||||
if (ret == NULL) error (EXIT_FAILURE, errno, "malloc");
|
||||
ret[0] = NULL;
|
||||
|
||||
while (errno = 0, (len = getline (&line, &buflen, fp)) != -1) {
|
||||
char *p;
|
||||
char *key, *value;
|
||||
|
||||
if (len > 0 && line[len-1] == '\n')
|
||||
line[len-1] = '\0';
|
||||
|
||||
/* Split the line at the first ':' character. */
|
||||
p = strchr (line, ':');
|
||||
if (p == NULL)
|
||||
continue;
|
||||
|
||||
*p = '\0';
|
||||
key = strdup (line);
|
||||
/* Skip leading whitespace in the value. */
|
||||
for (++p; *p && c_isspace (*p); ++p)
|
||||
;
|
||||
value = strdup (p);
|
||||
|
||||
/* Add key and value to the list, and trailing NULL pointer. */
|
||||
ret_size += 2;
|
||||
ret = realloc (ret, (ret_size + 1) * sizeof (char *));
|
||||
if (ret == NULL) error (EXIT_FAILURE, errno, "realloc");
|
||||
ret[ret_size-2] = key;
|
||||
ret[ret_size-1] = value;
|
||||
ret[ret_size] = NULL;
|
||||
}
|
||||
|
||||
if (errno) {
|
||||
perror (cmd);
|
||||
guestfs_int_free_string_list (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a single field from lscpu output.
|
||||
*
|
||||
* If the field does not exist, returns C<NULL>.
|
||||
*/
|
||||
static const char *
|
||||
get_field (char **lscpu, const char *key)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; lscpu[i] != NULL; i += 2) {
|
||||
if (STREQ (lscpu[i], key))
|
||||
return lscpu[i+1];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the CPU vendor from lscpu output.
|
||||
*/
|
||||
static void
|
||||
get_vendor (char **lscpu, struct cpu_config *cpu)
|
||||
{
|
||||
const char *vendor = get_field (lscpu, "Vendor ID");
|
||||
|
||||
if (vendor) {
|
||||
/* Note this mapping comes from /usr/share/libvirt/cpu_map.xml */
|
||||
if (STREQ (vendor, "GenuineIntel"))
|
||||
cpu->vendor = strdup ("Intel");
|
||||
else if (STREQ (vendor, "AuthenticAMD"))
|
||||
cpu->vendor = strdup ("AMD");
|
||||
/* Currently aarch64 lscpu has no Vendor ID XXX. */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the CPU topology from lscpu output.
|
||||
*/
|
||||
static void
|
||||
get_topology (char **lscpu, struct cpu_config *cpu)
|
||||
{
|
||||
const char *v;
|
||||
|
||||
v = get_field (lscpu, "Socket(s)");
|
||||
if (v)
|
||||
ignore_value (sscanf (v, "%u", &cpu->sockets));
|
||||
v = get_field (lscpu, "Core(s) per socket");
|
||||
if (v)
|
||||
ignore_value (sscanf (v, "%u", &cpu->cores));
|
||||
v = get_field (lscpu, "Thread(s) per core");
|
||||
if (v)
|
||||
ignore_value (sscanf (v, "%u", &cpu->threads));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read some important flags from lscpu output.
|
||||
*/
|
||||
static void
|
||||
get_flags (char **lscpu, struct cpu_config *cpu)
|
||||
{
|
||||
const char *flags;
|
||||
|
||||
flags = get_field (lscpu, "Flags");
|
||||
if (flags) {
|
||||
cpu->apic = strstr (flags, " apic ") != NULL;
|
||||
cpu->pae = strstr (flags, " pae ") != NULL;
|
||||
|
||||
/* aarch64 /proc/cpuinfo has a "Features" field, but lscpu does
|
||||
* not expose it. However aarch64 Features does not contain any
|
||||
* of the interesting flags above.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out if the system uses ACPI.
|
||||
*/
|
||||
static void
|
||||
get_acpi (struct cpu_config *cpu)
|
||||
{
|
||||
cpu->acpi = access ("/sys/firmware/acpi", F_OK) == 0;
|
||||
}
|
||||
|
||||
void
|
||||
get_cpu_config (struct cpu_config *cpu)
|
||||
{
|
||||
CLEANUP_FREE_STRING_LIST char **lscpu = NULL;
|
||||
|
||||
free_cpu_config (cpu);
|
||||
|
||||
lscpu = get_lscpu ();
|
||||
if (lscpu != NULL) {
|
||||
get_vendor (lscpu, cpu);
|
||||
get_topology (lscpu, cpu);
|
||||
get_flags (lscpu, cpu);
|
||||
}
|
||||
|
||||
get_acpi (cpu);
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
dnl This is the list of distro packages which are required by
|
||||
dnl virt-p2v.
|
||||
dnl
|
||||
dnl This file is processed by m4 with only one of the following
|
||||
dnl symbols defined (depending on the target distro):
|
||||
dnl
|
||||
dnl REDHAT=1 Fedora, RHEL, CentOS, SL and workalikes
|
||||
dnl DEBIAN=1 Debian and Ubuntu
|
||||
dnl ARCHLINUX=1 Arch Linux
|
||||
dnl SUSE=1 SUSE, OpenSUSE
|
||||
dnl OPENMANDRIVA=1 OpenMandriva
|
||||
dnl
|
||||
dnl NB 1: Must be one package name per line. Blank lines are ignored.
|
||||
dnl
|
||||
dnl NB 2: This works differently from appliance/packagelist.in
|
||||
dnl because we don't care about the current DISTRO (the one on
|
||||
dnl which libguestfs is being compiled), since we can "cross-build"
|
||||
dnl the virt-p2v ISO to any other Linux distro.
|
||||
dnl
|
||||
dnl NB 3: libguestfs is not a dependency of virt-p2v. libguestfs
|
||||
dnl only runs on the virt-v2v conversion server.
|
||||
|
||||
ifelse(REDHAT,1,
|
||||
dnl Used by the virt-p2v binary.
|
||||
pcre
|
||||
libxml2
|
||||
gtk`'GTK_VERSION
|
||||
dbus-libs
|
||||
|
||||
dnl Run as external programs by the p2v binary.
|
||||
/usr/bin/ssh
|
||||
/usr/bin/qemu-nbd
|
||||
which
|
||||
|
||||
dnl Generally useful tools to use within xterm
|
||||
vim-minimal
|
||||
|
||||
dnl Useful disk and diagnostic utilities.
|
||||
iscsi-initiator-utils
|
||||
|
||||
dnl X11 environment
|
||||
/usr/bin/xinit
|
||||
/usr/bin/Xorg
|
||||
xorg-x11-drivers
|
||||
xorg-x11-fonts-Type1
|
||||
dejavu-sans-fonts
|
||||
dejavu-sans-mono-fonts
|
||||
mesa-dri-drivers
|
||||
metacity
|
||||
|
||||
NetworkManager
|
||||
nm-connection-editor
|
||||
network-manager-applet
|
||||
dnl dbus is required by nm-applet, but not a dependency in Fedora
|
||||
dbus-x11
|
||||
dnl sysadmins prefer ifconfig
|
||||
net-tools
|
||||
|
||||
dnl RHBZ#1157679
|
||||
@hardware-support
|
||||
)
|
||||
|
||||
ifelse(DEBIAN,1,
|
||||
libpcre3
|
||||
libxml2
|
||||
ifelse(GTK_VERSION,2,libgtk`'GTK_VERSION`'.0-0,libgtk-`'GTK_VERSION`'-0)
|
||||
libdbus-1-3
|
||||
openssh-client
|
||||
qemu-utils
|
||||
debianutils
|
||||
vim-tiny
|
||||
open-iscsi
|
||||
xorg
|
||||
xserver-xorg-video-all
|
||||
fonts-dejavu
|
||||
metacity
|
||||
network-manager
|
||||
network-manager-gnome
|
||||
dbus-x11
|
||||
net-tools
|
||||
)
|
||||
|
||||
ifelse(ARCHLINUX,1,
|
||||
pcre
|
||||
libxml2
|
||||
gtk`'GTK_VERSION
|
||||
dbus
|
||||
openssh
|
||||
qemu
|
||||
which
|
||||
vim-tiny
|
||||
open-iscsi
|
||||
xorg-xinit
|
||||
xorg-server
|
||||
xf86-video-*
|
||||
ttf-dejavu
|
||||
metacity
|
||||
NetworkManager
|
||||
nm-connection-editor
|
||||
network-manager-applet
|
||||
dbus-x11
|
||||
net-tools
|
||||
)
|
||||
|
||||
ifelse(SUSE,1,
|
||||
pcre
|
||||
libxml2
|
||||
gtk`'GTK_VERSION
|
||||
libdbus-1-3
|
||||
qemu-tools
|
||||
openssh
|
||||
dnl /usr/bin/which is in util-linux on SUSE
|
||||
vim
|
||||
open-iscsi
|
||||
xinit
|
||||
xorg-x11-server
|
||||
xf86-video-*
|
||||
dejavu-fonts
|
||||
NetworkManager
|
||||
xf86-input-*
|
||||
icewm-lite
|
||||
dbus-1-x11
|
||||
yast2-network
|
||||
libyui-qt
|
||||
SuSEfirewall2
|
||||
)
|
||||
|
||||
ifelse(OPENMANDRIVA,1,
|
||||
dnl Used by the virt-p2v binary.
|
||||
pcre
|
||||
libxml2
|
||||
gtk`'GTK_VERSION
|
||||
dbus-libs
|
||||
|
||||
dnl Run as external programs by the p2v binary.
|
||||
/usr/bin/ssh
|
||||
/usr/bin/qemu-nbd
|
||||
which
|
||||
|
||||
dnl Generally useful tools to use within xterm
|
||||
vim-enhanced
|
||||
|
||||
dnl X11 environment
|
||||
/usr/bin/xinit
|
||||
/usr/bin/Xorg
|
||||
xorg-x11-drivers
|
||||
xorg-x11-fonts-Type1
|
||||
dejavu-sans-fonts
|
||||
dejavu-sans-mono-fonts
|
||||
mesa-dri-drivers
|
||||
kwin_x11
|
||||
|
||||
NetworkManager
|
||||
nm-connection-editor
|
||||
network-manager-applet
|
||||
dnl dbus is required by nm-applet, but not a dependency in Fedora
|
||||
dbus-x11
|
||||
dnl sysadmins prefer ifconfig
|
||||
net-tools
|
||||
)
|
||||
|
||||
dnl Run as external programs by the p2v binary.
|
||||
curl
|
||||
ethtool
|
||||
gawk
|
||||
lsscsi
|
||||
pciutils
|
||||
usbutils
|
||||
util-linux
|
||||
xterm
|
||||
|
||||
dnl Generally useful tools to use within xterm
|
||||
less
|
||||
|
||||
dnl The hwdata package contains PCI IDs, used by virt-p2v to display
|
||||
dnl network vendor information (RHBZ#855059).
|
||||
hwdata
|
||||
|
||||
dnl Useful disk and diagnostic utilities.
|
||||
hdparm
|
||||
smartmontools
|
||||
@@ -1,54 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
# 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.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# Clean up the program name.
|
||||
my $progname = $0;
|
||||
$progname =~ s{.*/}{};
|
||||
|
||||
my $filename = shift or die "$progname: missing filename";
|
||||
|
||||
open(my $fh, '<', $filename) or die "Unable to open file '$filename': $!";
|
||||
|
||||
print <<"EOF";
|
||||
/* libguestfs generated file
|
||||
* WARNING: THIS FILE IS GENERATED FROM THE FOLLOWING FILES:
|
||||
* $filename
|
||||
* ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "p2v.h"
|
||||
|
||||
/* Authors involved with virt-v2v and virt-p2v directly. */
|
||||
const char *authors[] = {
|
||||
EOF
|
||||
|
||||
while (<$fh>) {
|
||||
chomp $_;
|
||||
printf " \"%s\",\n", $_;
|
||||
}
|
||||
|
||||
print <<"EOF";
|
||||
NULL
|
||||
};
|
||||
EOF
|
||||
|
||||
close($fh);
|
||||
@@ -1,915 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
# 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.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Class::Struct;
|
||||
use Getopt::Long;
|
||||
use List::Util qw(any);
|
||||
|
||||
struct ConfigSection =>
|
||||
{
|
||||
name => '$',
|
||||
elements => '@',
|
||||
};
|
||||
|
||||
struct ConfigString =>
|
||||
{
|
||||
name => '$',
|
||||
};
|
||||
|
||||
struct ConfigInt =>
|
||||
{
|
||||
name => '$',
|
||||
value => '$',
|
||||
};
|
||||
|
||||
struct ConfigBool =>
|
||||
{
|
||||
name => '$',
|
||||
};
|
||||
|
||||
struct ConfigUInt64 =>
|
||||
{
|
||||
name => '$',
|
||||
};
|
||||
|
||||
struct ConfigUnsigned =>
|
||||
{
|
||||
name => '$',
|
||||
};
|
||||
|
||||
struct ConfigEnum =>
|
||||
{
|
||||
name => '$',
|
||||
enum => '$',
|
||||
};
|
||||
|
||||
struct ConfigStringList =>
|
||||
{
|
||||
name => '$',
|
||||
};
|
||||
|
||||
struct manual_entry =>
|
||||
{
|
||||
shortopt => '$',
|
||||
description => '$',
|
||||
};
|
||||
|
||||
# Enums.
|
||||
my @enums = (
|
||||
["basis", (
|
||||
["BASIS_UNKNOWN", "unknown", "RTC could not be read"],
|
||||
["BASIS_UTC", "utc", "RTC is either UTC or an offset from UTC"],
|
||||
["BASIS_LOCALTIME", "localtime", "RTC is localtime"],
|
||||
)],
|
||||
["output_allocation", (
|
||||
["OUTPUT_ALLOCATION_NONE", "none", "output allocation not set"],
|
||||
["OUTPUT_ALLOCATION_SPARSE", "sparse", "sparse"],
|
||||
["OUTPUT_ALLOCATION_PREALLOCATED", "preallocated", "preallocated"],
|
||||
)],
|
||||
);
|
||||
|
||||
# Configuration fields.
|
||||
my @fields = [
|
||||
ConfigSection->new(
|
||||
name => 'remote',
|
||||
elements => [
|
||||
ConfigString->new(name => 'server'),
|
||||
ConfigInt->new(name => 'port', value => 22),
|
||||
],
|
||||
),
|
||||
ConfigSection->new(
|
||||
name => 'auth',
|
||||
elements => [
|
||||
ConfigString->new(name => 'username'),
|
||||
ConfigString->new(name => 'password'),
|
||||
ConfigSection->new(
|
||||
name => 'identity',
|
||||
elements => [
|
||||
ConfigString->new(name => 'url'),
|
||||
ConfigString->new(name => 'file'),
|
||||
ConfigBool->new(name => 'file_needs_update'),
|
||||
],
|
||||
),
|
||||
ConfigBool->new(name => 'sudo'),
|
||||
],
|
||||
),
|
||||
ConfigString->new(name => 'guestname'),
|
||||
ConfigInt->new(name => 'vcpus', value => 0),
|
||||
ConfigUInt64->new(name => 'memory'),
|
||||
ConfigSection->new(
|
||||
name => 'cpu',
|
||||
elements => [
|
||||
ConfigString->new(name => 'vendor'),
|
||||
ConfigString->new(name => 'model'),
|
||||
ConfigUnsigned->new(name => 'sockets'),
|
||||
ConfigUnsigned->new(name => 'cores'),
|
||||
ConfigUnsigned->new(name => 'threads'),
|
||||
ConfigBool->new(name => 'acpi'),
|
||||
ConfigBool->new(name => 'apic'),
|
||||
ConfigBool->new(name => 'pae'),
|
||||
],
|
||||
),
|
||||
ConfigSection->new(
|
||||
name => 'rtc',
|
||||
elements => [
|
||||
ConfigEnum->new(name => 'basis', enum => 'basis'),
|
||||
ConfigInt->new(name => 'offset', value => 0),
|
||||
],
|
||||
),
|
||||
ConfigStringList->new(name => 'disks'),
|
||||
ConfigStringList->new(name => 'removable'),
|
||||
ConfigStringList->new(name => 'interfaces'),
|
||||
ConfigStringList->new(name => 'network_map'),
|
||||
ConfigSection->new(
|
||||
name => 'output',
|
||||
elements => [
|
||||
ConfigString->new(name => 'type'),
|
||||
ConfigEnum->new(name => 'allocation', enum => 'output_allocation'),
|
||||
ConfigString->new(name => 'connection'),
|
||||
ConfigString->new(name => 'format'),
|
||||
ConfigString->new(name => 'storage'),
|
||||
],
|
||||
),
|
||||
];
|
||||
|
||||
# Some /proc/cmdline p2v.* options were renamed when we introduced
|
||||
# the generator. This map creates backwards compatibility mappings
|
||||
# for these.
|
||||
my @cmdline_aliases = (
|
||||
["p2v.remote.server", "p2v.server"],
|
||||
["p2v.remote.port", "p2v.port"],
|
||||
["p2v.auth.username", "p2v.username"],
|
||||
["p2v.auth.password", "p2v.password"],
|
||||
["p2v.auth.identity.url", "p2v.identity"],
|
||||
["p2v.auth.sudo", "p2v.sudo"],
|
||||
["p2v.guestname", "p2v.name"],
|
||||
["p2v.network_map", "p2v.network"],
|
||||
["p2v.output.type", "p2v.o"],
|
||||
["p2v.output.allocation", "p2v.oa"],
|
||||
["p2v.output.connection", "p2v.oc"],
|
||||
["p2v.output.format", "p2v.of"],
|
||||
["p2v.output.storage", "p2v.os"],
|
||||
);
|
||||
|
||||
# Some config entries are not exposed on the kernel command line.
|
||||
my @cmdline_ignore = (
|
||||
"p2v.auth.identity.file",
|
||||
"p2v.auth.identity.file_needs_update",
|
||||
);
|
||||
|
||||
# Man page snippets for each kernel command line setting.
|
||||
my %cmdline_manual = (
|
||||
"p2v.remote.server" => manual_entry->new(
|
||||
shortopt => "SERVER",
|
||||
description => "
|
||||
The name or IP address of the conversion server.
|
||||
|
||||
This is always required if you are using the kernel configuration
|
||||
method. If virt-p2v does not find this on the kernel command line
|
||||
then it switches to the GUI (interactive) configuration method.",
|
||||
),
|
||||
"p2v.remote.port" => manual_entry->new(
|
||||
shortopt => "PORT",
|
||||
description => "
|
||||
The SSH port number on the conversion server (default: C<22>).",
|
||||
),
|
||||
"p2v.auth.username" => manual_entry->new(
|
||||
shortopt => "USERNAME",
|
||||
description => "
|
||||
The SSH username that we log in as on the conversion server
|
||||
(default: C<root>).",
|
||||
),
|
||||
"p2v.auth.password" => manual_entry->new(
|
||||
shortopt => "PASSWORD",
|
||||
description => "
|
||||
The SSH password that we use to log in to the conversion server.
|
||||
|
||||
The default is to try with no password. If this fails then virt-p2v
|
||||
will ask the user to type the password (probably several times during
|
||||
conversion).
|
||||
|
||||
This setting is ignored if C<p2v.auth.identity.url> is present.",
|
||||
),
|
||||
"p2v.auth.identity.url" => manual_entry->new(
|
||||
shortopt => "URL",
|
||||
description => "
|
||||
Provide a URL pointing to an SSH identity (private key) file. The URL
|
||||
is interpreted by L<curl(1)> so any URL that curl supports can be used
|
||||
here, including C<https://> and C<file://>. For more information on
|
||||
using SSH identities, see L</SSH IDENTITIES> below.
|
||||
|
||||
If C<p2v.auth.identity.url> is present, it overrides C<p2v.auth.password>.
|
||||
There is no fallback.",
|
||||
),
|
||||
"p2v.auth.sudo" => manual_entry->new(
|
||||
shortopt => "", # ignored for booleans
|
||||
description => "
|
||||
Use C<p2v.sudo> to tell virt-p2v to use L<sudo(8)> to gain root
|
||||
privileges on the conversion server after logging in as a non-root
|
||||
user (default: do not use sudo).",
|
||||
),
|
||||
"p2v.guestname" => manual_entry->new(
|
||||
shortopt => "GUESTNAME",
|
||||
description => "
|
||||
The name of the guest that is created. The default is to try to
|
||||
derive a name from the physical machine’s hostname (if possible) else
|
||||
use a randomly generated name.",
|
||||
),
|
||||
"p2v.vcpus" => manual_entry->new(
|
||||
shortopt => "N",
|
||||
description => "
|
||||
The number of virtual CPUs to give to the guest. The default is to
|
||||
use the same as the number of physical CPUs.",
|
||||
),
|
||||
"p2v.memory" => manual_entry->new(
|
||||
shortopt => "n(M|G)",
|
||||
description => "
|
||||
The size of the guest memory. You must specify the unit such as
|
||||
megabytes or gigabytes by using for example C<p2v.memory=1024M> or
|
||||
C<p2v.memory=1G>.
|
||||
|
||||
The default is to use the same amount of RAM as on the physical
|
||||
machine.",
|
||||
),
|
||||
"p2v.cpu.vendor" => manual_entry->new(
|
||||
shortopt => "VENDOR",
|
||||
description => "
|
||||
The vCPU vendor, eg. \"Intel\" or \"AMD\". The default is to use
|
||||
the same CPU vendor as the physical machine.",
|
||||
),
|
||||
"p2v.cpu.model" => manual_entry->new(
|
||||
shortopt => "MODEL",
|
||||
description => "
|
||||
The vCPU model, eg. \"IvyBridge\". The default is to use the same
|
||||
CPU model as the physical machine.",
|
||||
),
|
||||
"p2v.cpu.sockets" => manual_entry->new(
|
||||
shortopt => "N",
|
||||
description => "
|
||||
Number of vCPU sockets to use. The default is to use the same as the
|
||||
physical machine.",
|
||||
),
|
||||
"p2v.cpu.cores" => manual_entry->new(
|
||||
shortopt => "N",
|
||||
description => "
|
||||
Number of vCPU cores to use. The default is to use the same as the
|
||||
physical machine.",
|
||||
),
|
||||
"p2v.cpu.threads" => manual_entry->new(
|
||||
shortopt => "N",
|
||||
description => "
|
||||
Number of vCPU hyperthreads to use. The default is to use the same
|
||||
as the physical machine.",
|
||||
),
|
||||
"p2v.cpu.acpi" => manual_entry->new(
|
||||
shortopt => "", # ignored for booleans
|
||||
description => "
|
||||
Whether to enable ACPI in the remote virtual machine. The default is
|
||||
to use the same as the physical machine.",
|
||||
),
|
||||
"p2v.cpu.apic" => manual_entry->new(
|
||||
shortopt => "", # ignored for booleans
|
||||
description => "
|
||||
Whether to enable APIC in the remote virtual machine. The default is
|
||||
to use the same as the physical machine.",
|
||||
),
|
||||
"p2v.cpu.pae" => manual_entry->new(
|
||||
shortopt => "", # ignored for booleans
|
||||
description => "
|
||||
Whether to enable PAE in the remote virtual machine. The default is
|
||||
to use the same as the physical machine.",
|
||||
),
|
||||
"p2v.rtc.basis" => manual_entry->new(
|
||||
shortopt => "", # ignored for enums
|
||||
description => "
|
||||
Set the basis of the Real Time Clock in the virtual machine. The
|
||||
default is to try to detect this setting from the physical machine.",
|
||||
),
|
||||
"p2v.rtc.offset" => manual_entry->new(
|
||||
shortopt => "[+|-]HOURS",
|
||||
description => "
|
||||
The offset of the Real Time Clock from UTC. The default is to try
|
||||
to detect this setting from the physical machine.",
|
||||
),
|
||||
"p2v.disks" => manual_entry->new(
|
||||
shortopt => "sda,sdb,...",
|
||||
description => "
|
||||
A list of physical hard disks to convert, for example:
|
||||
|
||||
p2v.disks=sda,sdc
|
||||
|
||||
The default is to convert all local hard disks that are found.",
|
||||
),
|
||||
"p2v.removable" => manual_entry->new(
|
||||
shortopt => "sra,srb,...",
|
||||
description => "
|
||||
A list of removable media to convert. The default is to create
|
||||
virtual removable devices for every physical removable device found.
|
||||
Note that the content of removable media is never copied over.",
|
||||
),
|
||||
"p2v.interfaces" => manual_entry->new(
|
||||
shortopt => "em1,...",
|
||||
description => "
|
||||
A list of network interfaces to convert. The default is to create
|
||||
virtual network interfaces for every physical network interface found.",
|
||||
),
|
||||
"p2v.network_map" => manual_entry->new(
|
||||
shortopt => "interface:target,...",
|
||||
description => "
|
||||
Controls how network interfaces are connected to virtual networks on
|
||||
the target hypervisor. The default is to connect all network
|
||||
interfaces to the target C<default> network.
|
||||
|
||||
You give a comma-separated list of C<interface:target> pairs, plus
|
||||
optionally a default target. For example:
|
||||
|
||||
p2v.network=em1:ovirtmgmt
|
||||
|
||||
maps interface C<em1> to target network C<ovirtmgmt>.
|
||||
|
||||
p2v.network=em1:ovirtmgmt,em2:management,other
|
||||
|
||||
maps interface C<em1> to C<ovirtmgmt>, and C<em2> to C<management>,
|
||||
and any other interface that is found to C<other>.",
|
||||
),
|
||||
"p2v.output.type" => manual_entry->new(
|
||||
shortopt => "(libvirt|local|...)",
|
||||
description => "
|
||||
Set the output mode. This is the same as the virt-v2v I<-o> option.
|
||||
See L<virt-v2v(1)/OPTIONS>.
|
||||
|
||||
If not specified, the default is C<local>, and the converted guest is
|
||||
written to F</var/tmp>.",
|
||||
),
|
||||
"p2v.output.allocation" => manual_entry->new(
|
||||
shortopt => "", # ignored for enums
|
||||
description => "
|
||||
Set the output allocation mode. This is the same as the virt-v2v
|
||||
I<-oa> option. See L<virt-v2v(1)/OPTIONS>.",
|
||||
),
|
||||
"p2v.output.connection" => manual_entry->new(
|
||||
shortopt => "URI",
|
||||
description => "
|
||||
Set the output connection libvirt URI. This is the same as the
|
||||
virt-v2v I<-oc> option. See L<virt-v2v(1)/OPTIONS> and
|
||||
L<http://libvirt.org/uri.html>",
|
||||
),
|
||||
"p2v.output.format" => manual_entry->new(
|
||||
shortopt => "(raw|qcow2|...)",
|
||||
description => "
|
||||
Set the output format. This is the same as the virt-v2v I<-of>
|
||||
option. See L<virt-v2v(1)/OPTIONS>.",
|
||||
),
|
||||
"p2v.output.storage" => manual_entry->new(
|
||||
shortopt => "STORAGE",
|
||||
description => "
|
||||
Set the output storage. This is the same as the virt-v2v I<-os>
|
||||
option. See L<virt-v2v(1)/OPTIONS>.
|
||||
|
||||
If not specified, the default is F</var/tmp> (on the conversion server).",
|
||||
),
|
||||
);
|
||||
|
||||
# Clean up the program name.
|
||||
my $progname = $0;
|
||||
$progname =~ s{.*/}{};
|
||||
|
||||
my $filename;
|
||||
my $output;
|
||||
|
||||
GetOptions(
|
||||
'file=s' => \$filename,
|
||||
'output=s' => \$output,
|
||||
'help' => sub { pod2usage(1); },
|
||||
) or pod2usage(2);
|
||||
die "$progname: Option --file not specified.\n" unless $filename;
|
||||
# die "$progname: Option --output not specified.\n" unless $output;
|
||||
|
||||
sub print_generated_header {
|
||||
my $fh = shift;
|
||||
print $fh <<"EOF";
|
||||
/* libguestfs generated file
|
||||
* WARNING: THIS FILE IS GENERATED FROM THE FOLLOWING FILES:
|
||||
* $filename
|
||||
* ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.
|
||||
*/
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
sub generate_config_struct {
|
||||
my ($fh, $name, $fields) = @_;
|
||||
# If there are any ConfigSection (sub-structs) in any of the
|
||||
# fields then output those first.
|
||||
foreach my $field (@$fields) {
|
||||
if (ref($field) eq 'ConfigSection') {
|
||||
generate_config_struct($fh, $field->name . "_config", $field->elements);
|
||||
}
|
||||
}
|
||||
|
||||
# Now generate this struct.
|
||||
print $fh "struct $name {\n";
|
||||
foreach my $field (@$fields) {
|
||||
my $type = ref($field);
|
||||
if ($type eq 'ConfigSection') {
|
||||
printf $fh " struct %s_config %s;\n", $field->name, $field->name;
|
||||
} elsif ($type eq 'ConfigString') {
|
||||
printf $fh " char *%s;\n", $field->name;
|
||||
} elsif ($type eq 'ConfigInt') {
|
||||
printf $fh " int %s;\n", $field->name;
|
||||
} elsif ($type eq 'ConfigBool') {
|
||||
printf $fh " bool %s;\n", $field->name;
|
||||
} elsif ($type eq 'ConfigUInt64') {
|
||||
printf $fh " uint64_t %s;\n", $field->name;
|
||||
} elsif ($type eq 'ConfigUnsigned') {
|
||||
printf $fh " unsigned %s;\n", $field->name;
|
||||
} elsif ($type eq 'ConfigEnum') {
|
||||
printf $fh " enum %s %s;\n", $field->enum, $field->name;
|
||||
} elsif ($type eq 'ConfigStringList') {
|
||||
printf $fh " char **%s;\n", $field->name;
|
||||
}
|
||||
}
|
||||
print $fh "};\n";
|
||||
print $fh "\n"
|
||||
}
|
||||
|
||||
sub generate_p2v_config_h {
|
||||
my $fh = shift;
|
||||
print_generated_header($fh);
|
||||
print $fh <<"EOF";
|
||||
#ifndef GUESTFS_P2V_CONFIG_H
|
||||
#define GUESTFS_P2V_CONFIG_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
EOF
|
||||
|
||||
# Generate enums.
|
||||
foreach my $enum (@enums) {
|
||||
my $name = shift @$enum;
|
||||
print $fh "enum $name {\n";
|
||||
foreach my $items (@$enum) {
|
||||
my ($n, $foo, $comment) = @$items;
|
||||
printf $fh " %-25s /* %s */\n", ($n . ","), $comment;
|
||||
}
|
||||
print $fh "};\n";
|
||||
print $fh "\n"
|
||||
}
|
||||
|
||||
# Generate struct config.
|
||||
generate_config_struct($fh, "config", @fields);
|
||||
|
||||
print $fh <<'EOF';
|
||||
extern struct config *new_config (void);
|
||||
extern struct config *copy_config (struct config *);
|
||||
extern void free_config (struct config *);
|
||||
extern void print_config (struct config *, FILE *);
|
||||
|
||||
#endif /* GUESTFS_P2V_CONFIG_H */
|
||||
EOF
|
||||
}
|
||||
|
||||
sub generate_field_initialization {
|
||||
my ($fh, $v, $fields) = @_;
|
||||
foreach my $field (@$fields) {
|
||||
my $type = ref($field);
|
||||
if ($type eq 'ConfigSection') {
|
||||
my $lv = $v . $field->name . '.';
|
||||
generate_field_initialization($fh, $lv, $field->elements);
|
||||
} elsif ($type eq 'ConfigInt') {
|
||||
if ($field->value > 0) {
|
||||
printf $fh " %s%s = %d;\n", $v, $field->name, $field->value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub generate_field_copy {
|
||||
my ($fh, $v, $fields) = @_;
|
||||
foreach my $field (@$fields) {
|
||||
my $type = ref($field);
|
||||
if ($type eq 'ConfigSection') {
|
||||
my $lv = $v . $field->name . '.';
|
||||
generate_field_copy($fh, $lv, $field->elements);
|
||||
} elsif ($type eq 'ConfigString') {
|
||||
printf $fh " if (%s%s) {\n", $v, $field->name;
|
||||
printf $fh " %s%s = strdup (%s%s);\n", $v, $field->name, $v, $field->name;
|
||||
printf $fh " if (%s%s == NULL)\n", $v, $field->name;
|
||||
printf $fh " error (EXIT_FAILURE, errno, \"strdup: %%s\", \"%s\");\n", $field->name;
|
||||
printf $fh " }\n";
|
||||
} elsif ($type eq 'ConfigStringList') {
|
||||
printf $fh " if (%s%s) {\n", $v, $field->name;
|
||||
printf $fh " %s%s = guestfs_int_copy_string_list (%s%s);\n", $v, $field->name, $v, $field->name;
|
||||
printf $fh " if (%s%s == NULL)\n", $v, $field->name;
|
||||
printf $fh " error (EXIT_FAILURE, errno, \"copy string list: %%s\", \"%s\");\n", $field->name;
|
||||
printf $fh " }\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub generate_field_free {
|
||||
my ($fh, $v, $fields) = @_;
|
||||
foreach my $field (@$fields) {
|
||||
my $type = ref($field);
|
||||
if ($type eq 'ConfigSection') {
|
||||
my $lv = $v . $field->name . '.';
|
||||
generate_field_free($fh, $lv, $field->elements);
|
||||
} elsif ($type eq 'ConfigString') {
|
||||
printf $fh " free (%s%s);\n", $v, $field->name;
|
||||
} elsif ($type eq 'ConfigStringList') {
|
||||
printf $fh " guestfs_int_free_string_list (%s%s);\n", $v, $field->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub generate_field_print {
|
||||
my ($fh, $prefix, $v, $fields) = @_;
|
||||
foreach my $field (@$fields) {
|
||||
my $type = ref($field);
|
||||
my $printable_name = defined($prefix)
|
||||
? $prefix . '.' . $field->name
|
||||
: $field->name;
|
||||
if ($type eq 'ConfigSection') {
|
||||
my $lv = $v . $field->name . '.';
|
||||
generate_field_print($fh, $printable_name, $lv, $field->elements);
|
||||
} elsif ($type eq 'ConfigString') {
|
||||
print $fh " fprintf (fp, \"%-20s %s\\n\",\n";
|
||||
printf $fh " \"%s\", %s%s ? %s%s : \"(none)\");\n",
|
||||
$printable_name, $v, $field->name, $v, $field->name;
|
||||
} elsif ($type eq 'ConfigInt') {
|
||||
print $fh " fprintf (fp, \"%-20s %d\\n\",\n";
|
||||
printf $fh " \"%s\", %s%s);\n", $printable_name, $v, $field->name;
|
||||
} elsif ($type eq 'ConfigBool') {
|
||||
print $fh " fprintf (fp, \"%-20s %s\\n\",\n";
|
||||
printf $fh " \"%s\", %s%s ? \"true\" : \"false\");\n",
|
||||
$printable_name, $v, $field->name;
|
||||
} elsif ($type eq 'ConfigUInt64') {
|
||||
print $fh " fprintf (fp, \"%-20s %\" PRIu64 \"\\n\",\n";
|
||||
printf $fh " \"%s\", %s%s);\n", $printable_name, $v, $field->name;
|
||||
} elsif ($type eq 'ConfigUnsigned') {
|
||||
print $fh " fprintf (fp, \"%-20s %u\\n\",\n";
|
||||
printf $fh " \"%s\", %s%s);\n", $printable_name, $v, $field->name;
|
||||
} elsif ($type eq 'ConfigEnum') {
|
||||
printf $fh " fprintf (fp, \"%%-20s \", \"%s\");\n", $printable_name;
|
||||
printf $fh " print_%s (%s%s, fp);\n", $field->enum, $v, $field->name;
|
||||
print $fh " fprintf (fp, \"\\n\");\n";
|
||||
} elsif ($type eq 'ConfigStringList') {
|
||||
printf $fh " fprintf (fp, \"%%-20s\", \"%s\");\n", $printable_name;
|
||||
printf $fh " if (%s%s) {\n", $v, $field->name;
|
||||
printf $fh " for (i = 0; %s%s[i] != NULL; ++i)\n", $v, $field->name;
|
||||
printf $fh " fprintf (fp, \" %%s\", %s%s[i]);\n", $v, $field->name;
|
||||
print $fh " }\n";
|
||||
print $fh " else\n";
|
||||
print $fh " fprintf (fp, \" (none)\\n\");\n";
|
||||
print $fh " fprintf (fp, \"\\n\");\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub generate_p2v_config_c {
|
||||
my $fh = shift;
|
||||
print_generated_header($fh);
|
||||
print $fh <<"EOF";
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
|
||||
#include "p2v.h"
|
||||
#include "p2v-config.h"
|
||||
|
||||
/**
|
||||
* Allocate a new config struct.
|
||||
*/
|
||||
struct config *
|
||||
new_config (void)
|
||||
{
|
||||
struct config *c;
|
||||
|
||||
c = calloc (1, sizeof *c);
|
||||
if (c == NULL)
|
||||
error (EXIT_FAILURE, errno, "calloc");
|
||||
|
||||
EOF
|
||||
|
||||
generate_field_initialization($fh, "c->", @fields);
|
||||
|
||||
print $fh <<"EOF";
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a config struct.
|
||||
*/
|
||||
struct config *
|
||||
copy_config (struct config *old)
|
||||
{
|
||||
struct config *c = new_config ();
|
||||
|
||||
memcpy (c, old, sizeof *c);
|
||||
|
||||
/* Need to deep copy strings and string lists. */
|
||||
EOF
|
||||
|
||||
generate_field_copy($fh, "c->", @fields);
|
||||
|
||||
print $fh <<"EOF";
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a config struct.
|
||||
*/
|
||||
void
|
||||
free_config (struct config *c)
|
||||
{
|
||||
if (c == NULL)
|
||||
return;
|
||||
|
||||
EOF
|
||||
|
||||
generate_field_free($fh, "c->", @fields);
|
||||
|
||||
print $fh <<"EOF";
|
||||
}
|
||||
|
||||
EOF
|
||||
|
||||
foreach my $enum (@enums) {
|
||||
my $name = shift @$enum;
|
||||
print $fh "static void\n";
|
||||
printf $fh "print_%s (enum %s v, FILE *fp)\n", $name, $name;
|
||||
print $fh "{\n";
|
||||
printf $fh " switch (v) {\n";
|
||||
foreach my $items (@$enum) {
|
||||
my ($n, $cmdline, $foo) = @$items;
|
||||
printf $fh " case %s:\n", $n;
|
||||
printf $fh " fprintf (fp, \"%s\");\n", $cmdline;
|
||||
print $fh " break;\n";
|
||||
}
|
||||
print $fh " }\n";
|
||||
print $fh "}\n";
|
||||
print $fh "\n"
|
||||
}
|
||||
|
||||
print $fh <<"EOF";
|
||||
/**
|
||||
* Print the conversion parameters and other important information.
|
||||
*/
|
||||
void
|
||||
print_config (struct config *c, FILE *fp)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
fprintf (fp, \"%-20s %s\\n\", \"local version\", PACKAGE_VERSION_FULL);
|
||||
fprintf (fp, \"%-20s %s\\n\", \"remote version\",
|
||||
v2v_version ? v2v_version : \"unknown\");
|
||||
EOF
|
||||
|
||||
generate_field_print($fh, undef, "c->", @fields);
|
||||
|
||||
print $fh <<"EOF";
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
sub find_alias {
|
||||
my $name = shift;
|
||||
foreach my $alias (@cmdline_aliases) {
|
||||
if ($name eq @$alias[0]) {
|
||||
return @$alias[1];
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub find_enum {
|
||||
my $name = shift;
|
||||
foreach my $enum (@enums) {
|
||||
my $n = shift @$enum;
|
||||
if ($n eq $name) {
|
||||
return @$enum;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub generate_field_config {
|
||||
my ($fh, $prefix, $v, $fields) = @_;
|
||||
|
||||
foreach my $field (@$fields) {
|
||||
my $type = ref($field);
|
||||
if ($type eq 'ConfigSection') {
|
||||
my $lprefix = $prefix . '.' . $field->name;
|
||||
my $lv = $v . $field->name . '.';
|
||||
generate_field_config($fh, $lprefix, $lv, $field->elements);
|
||||
} else {
|
||||
my $key = $prefix . '.' . $field->name;
|
||||
|
||||
if (not (any { $_ eq $key } @cmdline_ignore)) {
|
||||
# Is there an alias for this field?
|
||||
my $alias = find_alias($key);
|
||||
|
||||
printf $fh " if ((p = get_cmdline_key (cmdline, \"%s\")) != NULL", $key;
|
||||
if (defined($alias)) {
|
||||
print $fh " ||\n";
|
||||
printf $fh " (p = get_cmdline_key (cmdline, \"%s\")) != NULL", $alias;
|
||||
}
|
||||
print $fh ") {\n";
|
||||
|
||||
# Parse the field.
|
||||
if ($type eq 'ConfigString') {
|
||||
printf $fh " free (%s%s);\n", $v, $field->name;
|
||||
printf $fh " %s%s = strdup (p);\n", $v, $field->name;
|
||||
printf $fh " if (%s%s == NULL)\n", $v, $field->name;
|
||||
print $fh " error (EXIT_FAILURE, errno, \"strdup\");\n";
|
||||
} elsif ($type eq 'ConfigInt') {
|
||||
printf $fh " if (sscanf (p, \"%%d\", &%s%s) != 1)\n", $v, $field->name;
|
||||
print $fh " error (EXIT_FAILURE, errno,\n";
|
||||
print $fh " \"cannot parse %s=%s from the kernel command line\",\n";
|
||||
printf $fh " \"%s\", p);\n", $key;
|
||||
} elsif ($type eq 'ConfigBool') {
|
||||
printf $fh " %s%s = guestfs_int_is_true (p) || STREQ (p, \"\");\n", $v, $field->name;
|
||||
} elsif ($type eq 'ConfigUInt64') {
|
||||
print $fh " xerr = xstrtoull (p, NULL, 0, &ull, \"0kKMGTPEZY\");\n";
|
||||
print $fh " if (xerr != LONGINT_OK)\n";
|
||||
print $fh " error (EXIT_FAILURE, 0,\n";
|
||||
print $fh " \"cannot parse %s=%s from the kernel command line\",\n";
|
||||
printf $fh " \"%s\", p);\n", $key;
|
||||
printf $fh " %s%s = ull;\n", $v, $field->name;
|
||||
} elsif ($type eq 'ConfigUnsigned') {
|
||||
printf $fh " if (sscanf (p, \"%%u\", &%s%s) != 1)\n", $v, $field->name;
|
||||
print $fh " error (EXIT_FAILURE, errno,\n";
|
||||
print $fh " \"cannot parse %s=%s from the kernel command line\",\n";
|
||||
printf $fh " \"%s\", p);\n", $key;
|
||||
} elsif ($type eq 'ConfigEnum') {
|
||||
my @enum_choices = find_enum($field->enum) or die "cannot find ConfigEnum $field->enum";
|
||||
printf $fh " ";
|
||||
foreach my $items (@enum_choices) {
|
||||
my ($n, $cmdline, $foo) = @$items;
|
||||
printf $fh "if (STREQ (p, \"%s\"))\n", $cmdline;
|
||||
printf $fh " %s%s = %s;\n", $v, $field->name, $n;
|
||||
print $fh " else ";
|
||||
}
|
||||
print $fh "{\n";
|
||||
print $fh " error (EXIT_FAILURE, 0,\n";
|
||||
print $fh " \"invalid value %s=%s from the kernel command line\",\n";
|
||||
printf $fh " \"%s\", p);\n", $key;
|
||||
print $fh " }\n";
|
||||
} elsif ($type eq 'ConfigStringList') {
|
||||
printf $fh " guestfs_int_free_string_list (%s%s);\n", $v, $field->name;
|
||||
printf $fh " %s%s = guestfs_int_split_string (',', p);\n", $v, $field->name;
|
||||
printf $fh " if (%s%s == NULL)\n", $v, $field->name;
|
||||
print $fh " error (EXIT_FAILURE, errno, \"strdup\");\n";
|
||||
}
|
||||
|
||||
print $fh " }\n";
|
||||
print $fh "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub generate_p2v_kernel_config_c {
|
||||
my $fh = shift;
|
||||
print_generated_header($fh);
|
||||
print $fh <<"EOF";
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
|
||||
#include "xstrtol.h"
|
||||
|
||||
#include "p2v.h"
|
||||
#include "p2v-config.h"
|
||||
|
||||
/**
|
||||
* Read the kernel command line and parse out any C<p2v.*> fields that
|
||||
* we understand into the config struct.
|
||||
*/
|
||||
void
|
||||
update_config_from_kernel_cmdline (struct config *c, char **cmdline)
|
||||
{
|
||||
const char *p;
|
||||
strtol_error xerr;
|
||||
unsigned long long ull;
|
||||
|
||||
EOF
|
||||
|
||||
generate_field_config($fh, "p2v", "c->", @fields);
|
||||
|
||||
print $fh <<"EOF";
|
||||
if (c->auth.identity.url != NULL)
|
||||
c->auth.identity.file_needs_update = 1;
|
||||
|
||||
/* Undocumented command line parameter used for testing command line
|
||||
* parsing.
|
||||
*/
|
||||
p = get_cmdline_key (cmdline, "p2v.dump_config_and_exit");
|
||||
if (p) {
|
||||
print_config (c, stdout);
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
sub generate_field_config_pod {
|
||||
my ($fh, $prefix, $fields) = @_;
|
||||
|
||||
foreach my $field (@$fields) {
|
||||
my $type = ref($field);
|
||||
if ($type eq 'ConfigSection') {
|
||||
my $lprefix = $prefix . '.' . $field->name;
|
||||
generate_field_config_pod($fh, $lprefix, $field->elements);
|
||||
} else {
|
||||
my $key = $prefix . '.' . $field->name;
|
||||
|
||||
if (not (any { $_ eq $key } @cmdline_ignore)) {
|
||||
# Is there an alias for this field?
|
||||
my $manual_entry = $cmdline_manual{$key} or die "missing manual entry for $key";
|
||||
|
||||
# For booleans there is no shortopt field. For enums
|
||||
# we generate it.
|
||||
my $shortopt;
|
||||
if ($type eq 'ConfigBool') {
|
||||
die "non-empty shortopt for $field->name" if $manual_entry->shortopt ne '';
|
||||
$shortopt = '';
|
||||
} elsif ($type eq 'ConfigEnum') {
|
||||
die "non-empty shortopt for $field->name" if $manual_entry->shortopt ne '';
|
||||
my @enum_choices = find_enum($field->enum) or die "cannot find ConfigEnum $field->enum";
|
||||
$shortopt = "=(" . join('|', map { $_->[1] } @enum_choices) . ")";
|
||||
} else {
|
||||
$shortopt = "=" . $manual_entry->shortopt;
|
||||
}
|
||||
|
||||
# The description must not end with \n
|
||||
die "description of $key must not end with \\n" if $manual_entry->description =~ /\n\z/;
|
||||
|
||||
# Is there an alias for this field?
|
||||
my $alias = find_alias($key);
|
||||
printf $fh "=item B<%s%s>\n\n", $key, $shortopt;
|
||||
if (defined($alias)) {
|
||||
printf $fh "=item B<%s%s>\n\n", $alias, $shortopt;
|
||||
}
|
||||
|
||||
printf $fh "%s\n\n", $manual_entry->description;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub write_to {
|
||||
my $fn = shift;
|
||||
if (defined($output)) {
|
||||
open(my $fh, '>', $output) or die "Could not open file '$output': $!";
|
||||
$fn->($fh, @_);
|
||||
close($fh);
|
||||
} else {
|
||||
$fn->(*STDOUT, @_);
|
||||
}
|
||||
}
|
||||
|
||||
if ($filename eq 'config.c') {
|
||||
write_to(\&generate_p2v_config_c);
|
||||
} elsif ($filename eq 'kernel-config.c') {
|
||||
write_to(\&generate_p2v_kernel_config_c);
|
||||
} elsif ($filename eq 'p2v-config.h') {
|
||||
write_to(\&generate_p2v_config_h);
|
||||
} elsif ($filename eq 'virt-p2v-kernel-config.pod') {
|
||||
write_to(\&generate_field_config_pod, "p2v", @fields);
|
||||
} else {
|
||||
die "$progname: unrecognized output file '$filename'\n";
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
/* virt-p2v
|
||||
* Copyright (C) 2009-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.
|
||||
*/
|
||||
|
||||
/* Backwards compatibility for ancient RHEL 5 Gtk 2.10. */
|
||||
#ifndef GTK_COMBO_BOX_TEXT
|
||||
#define GTK_COMBO_BOX_TEXT GTK_COMBO_BOX
|
||||
#define gtk_combo_box_text_new() gtk_combo_box_new_text()
|
||||
#define gtk_combo_box_text_append_text(combo, text) \
|
||||
gtk_combo_box_append_text((combo), (text))
|
||||
#define gtk_combo_box_text_get_active_text(combo) \
|
||||
gtk_combo_box_get_active_text((combo))
|
||||
#endif
|
||||
|
||||
#if !GTK_CHECK_VERSION(2,12,0) /* gtk < 2.12 */
|
||||
#define gtk_widget_set_tooltip_markup(widget, text) /* nothing */
|
||||
#endif
|
||||
|
||||
#if !GTK_CHECK_VERSION(2,14,0) /* gtk < 2.14 */
|
||||
#define gtk_dialog_get_content_area(dlg) ((dlg)->vbox)
|
||||
#endif
|
||||
|
||||
#if !GTK_CHECK_VERSION(2,18,0) /* gtk < 2.18 */
|
||||
static void
|
||||
gtk_cell_renderer_set_alignment (GtkCellRenderer *cell,
|
||||
gfloat xalign, gfloat yalign)
|
||||
{
|
||||
if ((xalign != cell->xalign) || (yalign != cell->yalign)) {
|
||||
g_object_freeze_notify (G_OBJECT (cell));
|
||||
|
||||
if (xalign != cell->xalign) {
|
||||
cell->xalign = xalign;
|
||||
g_object_notify (G_OBJECT (cell), "xalign");
|
||||
}
|
||||
|
||||
if (yalign != cell->yalign) {
|
||||
cell->yalign = yalign;
|
||||
g_object_notify (G_OBJECT (cell), "yalign");
|
||||
}
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (cell));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !GTK_CHECK_VERSION(2,20,0) /* gtk < 2.20 */
|
||||
typedef struct _ResponseData ResponseData;
|
||||
|
||||
struct _ResponseData
|
||||
{
|
||||
gint response_id;
|
||||
};
|
||||
|
||||
static void
|
||||
response_data_free (gpointer data)
|
||||
{
|
||||
g_slice_free (ResponseData, data);
|
||||
}
|
||||
|
||||
static ResponseData *
|
||||
get_response_data (GtkWidget *widget, gboolean create)
|
||||
{
|
||||
ResponseData *ad = g_object_get_data (G_OBJECT (widget),
|
||||
"gtk-dialog-response-data");
|
||||
|
||||
if (ad == NULL && create) {
|
||||
ad = g_slice_new (ResponseData);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (widget),
|
||||
g_intern_static_string ("gtk-dialog-response-data"),
|
||||
ad,
|
||||
response_data_free);
|
||||
}
|
||||
|
||||
return ad;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
gtk_dialog_get_widget_for_response (GtkDialog *dialog, gint response_id)
|
||||
{
|
||||
GList *children;
|
||||
GList *tmp_list;
|
||||
|
||||
children = gtk_container_get_children (GTK_CONTAINER (dialog->action_area));
|
||||
|
||||
tmp_list = children;
|
||||
while (tmp_list != NULL) {
|
||||
GtkWidget *widget = tmp_list->data;
|
||||
ResponseData *rd = get_response_data (widget, FALSE);
|
||||
|
||||
if (rd && rd->response_id == response_id) {
|
||||
g_list_free (children);
|
||||
return widget;
|
||||
}
|
||||
|
||||
tmp_list = tmp_list->next;
|
||||
}
|
||||
|
||||
g_list_free (children);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif /* gtk < 2.20 */
|
||||
@@ -1,140 +0,0 @@
|
||||
/* virt-p2v
|
||||
* Copyright (C) 2009-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.
|
||||
*/
|
||||
|
||||
/* Backwards compatibility for some deprecated functions in Gtk 3. */
|
||||
#if !GTK_CHECK_VERSION(3,2,0) /* gtk < 3.2 */
|
||||
static gboolean
|
||||
gdk_event_get_button (const GdkEvent *event, guint *button)
|
||||
{
|
||||
if (event->type != GDK_BUTTON_PRESS)
|
||||
return FALSE;
|
||||
|
||||
*button = ((const GdkEventButton *) event)->button;
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if GTK_CHECK_VERSION(3,2,0) /* gtk >= 3.2 */
|
||||
#define hbox_new(box, homogeneous, spacing) \
|
||||
do { \
|
||||
(box) = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, spacing); \
|
||||
if (homogeneous) \
|
||||
gtk_box_set_homogeneous (GTK_BOX (box), TRUE); \
|
||||
} while (0)
|
||||
#define vbox_new(box, homogeneous, spacing) \
|
||||
do { \
|
||||
(box) = gtk_box_new (GTK_ORIENTATION_VERTICAL, spacing); \
|
||||
if (homogeneous) \
|
||||
gtk_box_set_homogeneous (GTK_BOX (box), TRUE); \
|
||||
} while (0)
|
||||
#else /* gtk < 3.2 */
|
||||
#define hbox_new(box, homogeneous, spacing) \
|
||||
(box) = gtk_hbox_new ((homogeneous), (spacing))
|
||||
#define vbox_new(box, homogeneous, spacing) \
|
||||
(box) = gtk_vbox_new ((homogeneous), (spacing))
|
||||
#endif
|
||||
|
||||
#if GTK_CHECK_VERSION(3,4,0) /* gtk >= 3.4 */
|
||||
/* Copy this enum from GtkTable, as when building without deprecated
|
||||
* functions this is not automatically pulled in.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GTK_EXPAND = 1 << 0,
|
||||
GTK_SHRINK = 1 << 1,
|
||||
GTK_FILL = 1 << 2
|
||||
} GtkAttachOptions;
|
||||
/* GtkGrid is sufficiently similar to GtkTable that we can just
|
||||
* redefine these functions.
|
||||
*/
|
||||
#define table_new(grid, rows, columns) \
|
||||
(grid) = gtk_grid_new ()
|
||||
#define table_attach(grid, child, left, right, top, bottom, xoptions, yoptions, xpadding, ypadding) \
|
||||
do { \
|
||||
if (((xoptions) & GTK_EXPAND) != 0) \
|
||||
gtk_widget_set_hexpand ((child), TRUE); \
|
||||
if (((xoptions) & GTK_FILL) != 0) \
|
||||
gtk_widget_set_halign ((child), GTK_ALIGN_FILL); \
|
||||
if (((yoptions) & GTK_EXPAND) != 0) \
|
||||
gtk_widget_set_vexpand ((child), TRUE); \
|
||||
if (((yoptions) & GTK_FILL) != 0) \
|
||||
gtk_widget_set_valign ((child), GTK_ALIGN_FILL); \
|
||||
set_padding ((child), (xpadding), (ypadding)); \
|
||||
gtk_grid_attach (GTK_GRID (grid), (child), \
|
||||
(left), (top), (right)-(left), (bottom)-(top)); \
|
||||
} while (0)
|
||||
#else
|
||||
#define table_new(table, rows, columns) \
|
||||
(table) = gtk_table_new ((rows), (columns), FALSE)
|
||||
#define table_attach(table, child, left, right,top, bottom, xoptions, yoptions, xpadding, ypadding) \
|
||||
gtk_table_attach (GTK_TABLE (table), (child), \
|
||||
(left), (right), (top), (bottom), \
|
||||
(xoptions), (yoptions), (xpadding), (ypadding))
|
||||
#endif
|
||||
|
||||
#if GTK_CHECK_VERSION(3,8,0) /* gtk >= 3.8 */
|
||||
#define scrolled_window_add_with_viewport(container, child) \
|
||||
gtk_container_add (GTK_CONTAINER (container), child)
|
||||
#else
|
||||
#define scrolled_window_add_with_viewport(container, child) \
|
||||
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (container), child)
|
||||
#endif
|
||||
|
||||
#if !GTK_CHECK_VERSION(3,10,0) /* gtk < 3.10 */
|
||||
#define gdk_event_get_event_type(event) ((event)->type)
|
||||
#endif
|
||||
|
||||
#if GTK_CHECK_VERSION(3,10,0) /* gtk >= 3.10 */
|
||||
#undef GTK_STOCK_DIALOG_WARNING
|
||||
#define GTK_STOCK_DIALOG_WARNING "dialog-warning"
|
||||
#define gtk_image_new_from_stock gtk_image_new_from_icon_name
|
||||
#endif
|
||||
|
||||
#if GTK_CHECK_VERSION(3,14,0) /* gtk >= 3.14 */
|
||||
#define set_padding(widget, xpad, ypad) \
|
||||
do { \
|
||||
if ((xpad) != 0) { \
|
||||
gtk_widget_set_margin_start ((widget), (xpad)); \
|
||||
gtk_widget_set_margin_end ((widget), (xpad)); \
|
||||
} \
|
||||
if ((ypad) != 0) { \
|
||||
gtk_widget_set_margin_top ((widget), (ypad)); \
|
||||
gtk_widget_set_margin_bottom ((widget), (ypad)); \
|
||||
} \
|
||||
} while (0)
|
||||
#define set_alignment(widget, xalign, yalign) \
|
||||
do { \
|
||||
if ((xalign) == 0.) \
|
||||
gtk_widget_set_halign ((widget), GTK_ALIGN_START); \
|
||||
else if ((xalign) == 1.) \
|
||||
gtk_widget_set_halign ((widget), GTK_ALIGN_END); \
|
||||
else \
|
||||
gtk_widget_set_halign ((widget), GTK_ALIGN_CENTER); \
|
||||
if ((yalign) == 0.) \
|
||||
gtk_widget_set_valign ((widget), GTK_ALIGN_START); \
|
||||
else if ((xalign) == 1.) \
|
||||
gtk_widget_set_valign ((widget), GTK_ALIGN_END); \
|
||||
else \
|
||||
gtk_widget_set_valign ((widget), GTK_ALIGN_CENTER); \
|
||||
} while (0)
|
||||
#else /* gtk < 3.14 */
|
||||
#define set_padding(widget, xpad, ypad) \
|
||||
gtk_misc_set_padding(GTK_MISC(widget),(xpad),(ypad))
|
||||
#define set_alignment(widget, xalign, yalign) \
|
||||
gtk_misc_set_alignment(GTK_MISC(widget),(xalign),(yalign))
|
||||
#endif
|
||||
154
p2v/inhibit.c
154
p2v/inhibit.c
@@ -1,154 +0,0 @@
|
||||
/* virt-p2v
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file is used to inhibit power saving, sleep, suspend etc during
|
||||
* the conversion.
|
||||
*
|
||||
* The method it uses is to send a D-Bus message to logind, as
|
||||
* described here:
|
||||
*
|
||||
* https://www.freedesktop.org/wiki/Software/systemd/inhibit/
|
||||
*
|
||||
* If virt-p2v is compiled without D-Bus support then this does nothing.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(HAVE_DBUS)
|
||||
#include <dbus/dbus.h>
|
||||
#endif
|
||||
|
||||
#include "p2v.h"
|
||||
|
||||
/**
|
||||
* Inhibit all forms of power saving. A file descriptor is returned,
|
||||
* and when the file descriptor is closed the inhibit is stopped.
|
||||
*
|
||||
* If the function returns C<-1> then C<Inhibit> operation could not
|
||||
* be performed (eg. if we are compiled without D-Bus support, or there
|
||||
* is some error contacting logind). This is not usually fatal from
|
||||
* the point of view of the caller, conversion can continue.
|
||||
*/
|
||||
int
|
||||
inhibit_power_saving (void)
|
||||
{
|
||||
#if defined(HAVE_DBUS) && defined(DBUS_TYPE_UNIX_FD)
|
||||
DBusError err;
|
||||
DBusConnection *conn = NULL;
|
||||
DBusMessage *msg = NULL;
|
||||
DBusMessageIter args;
|
||||
DBusPendingCall *pending = NULL;
|
||||
const char *what = "shutdown:sleep:idle";
|
||||
const char *who = "virt-p2v";
|
||||
const char *why = "virt-p2v conversion is running";
|
||||
const char *mode = "block";
|
||||
int fd = -1;
|
||||
|
||||
dbus_error_init (&err);
|
||||
|
||||
conn = dbus_bus_get (DBUS_BUS_SYSTEM, &err);
|
||||
if (dbus_error_is_set (&err)) {
|
||||
fprintf (stderr, "inhibit_power_saving: dbus: cannot connect to system bus: %s\n", err.message);
|
||||
goto out;
|
||||
}
|
||||
if (conn == NULL)
|
||||
goto out;
|
||||
|
||||
msg = dbus_message_new_method_call ("org.freedesktop.login1",
|
||||
"/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
"Inhibit");
|
||||
if (msg == NULL) {
|
||||
fprintf (stderr, "inhibit_power_saving: dbus: cannot create message\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
dbus_message_iter_init_append (msg, &args);
|
||||
if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &what) ||
|
||||
!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &who) ||
|
||||
!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &why) ||
|
||||
!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &mode)) {
|
||||
fprintf (stderr, "inhibit_power_saving: dbus: cannot add message arguments\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!dbus_connection_send_with_reply (conn, msg, &pending, -1)) {
|
||||
fprintf (stderr, "inhibit_power_saving: dbus: cannot send Inhibit message to logind\n");
|
||||
goto out;
|
||||
}
|
||||
if (pending == NULL)
|
||||
goto out;
|
||||
dbus_connection_flush (conn);
|
||||
|
||||
dbus_message_unref (msg);
|
||||
msg = NULL;
|
||||
|
||||
dbus_pending_call_block (pending);
|
||||
msg = dbus_pending_call_steal_reply (pending);
|
||||
if (msg == NULL) {
|
||||
fprintf (stderr, "inhibit_power_saving: dbus: could not read message reply\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
dbus_pending_call_unref (pending);
|
||||
pending = NULL;
|
||||
|
||||
if (!dbus_message_iter_init (msg, &args)) {
|
||||
fprintf (stderr, "inhibit_power_saving: dbus: message reply has no return value\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dbus_message_iter_get_arg_type (&args) != DBUS_TYPE_UNIX_FD) {
|
||||
fprintf (stderr, "inhibit_power_saving: dbus: message reply is not a file descriptor\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
dbus_message_iter_get_basic (&args, &fd);
|
||||
|
||||
#ifdef DEBUG_STDERR
|
||||
fprintf (stderr, "inhibit_power_saving: dbus: Inhibit() call returned file descriptor %d\n", fd);
|
||||
#endif
|
||||
|
||||
out:
|
||||
if (pending != NULL)
|
||||
dbus_pending_call_unref (pending);
|
||||
if (msg != NULL)
|
||||
dbus_message_unref (msg);
|
||||
|
||||
/* This is the system bus connection, so unref-ing it does not
|
||||
* actually close it.
|
||||
*/
|
||||
if (conn != NULL)
|
||||
dbus_connection_unref (conn);
|
||||
|
||||
dbus_error_free (&err);
|
||||
|
||||
return fd;
|
||||
|
||||
#else /* !dbus */
|
||||
#ifdef DEBUG_STDERR
|
||||
fprintf (stderr, "warning: virt-p2v compiled without D-Bus support.\n");
|
||||
#endif
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
16
p2v/issue
16
p2v/issue
@@ -1,16 +0,0 @@
|
||||
virt-p2v - Convert a physical machine to use KVM.
|
||||
|
||||
***
|
||||
The root password is "p2v" (without quotes).
|
||||
|
||||
To see the status of virt-p2v, do:
|
||||
|
||||
systemctl status p2v -l
|
||||
|
||||
Virt-p2v may take some time to start up. If virt-p2v is not running
|
||||
after a few minutes, you can start it by typing:
|
||||
|
||||
launch-virt-p2v
|
||||
|
||||
***
|
||||
|
||||
@@ -1,196 +0,0 @@
|
||||
/* virt-p2v
|
||||
* Copyright (C) 2015 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Mini library to read and parse C</proc/cmdline>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
|
||||
#include "getprogname.h"
|
||||
|
||||
#include "p2v.h"
|
||||
|
||||
static void
|
||||
add_null (char ***argv, size_t *lenp)
|
||||
{
|
||||
(*lenp)++;
|
||||
*argv = realloc (*argv, *lenp * sizeof (char *));
|
||||
if (*argv == NULL)
|
||||
error (EXIT_FAILURE, errno, "realloc");
|
||||
(*argv)[(*lenp)-1] = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
add_string (char ***argv, size_t *lenp, const char *str, size_t len)
|
||||
{
|
||||
add_null (argv, lenp);
|
||||
(*argv)[(*lenp)-1] = strndup (str, len);
|
||||
if ((*argv)[(*lenp)-1] == NULL)
|
||||
error (EXIT_FAILURE, errno, "strndup");
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and parse C</proc/cmdline>.
|
||||
*
|
||||
* We only support double quoting, consistent with the Linux
|
||||
* documentation.
|
||||
* L<https://www.kernel.org/doc/Documentation/kernel-parameters.txt>
|
||||
*
|
||||
* systemd supports single and double quoting and single character
|
||||
* escaping, but we don't support all that.
|
||||
*
|
||||
* Returns a list of key, value pairs, terminated by C<NULL>.
|
||||
*/
|
||||
char **
|
||||
parse_cmdline_string (const char *cmdline)
|
||||
{
|
||||
char **ret = NULL;
|
||||
size_t len = 0;
|
||||
const char *p, *key = NULL, *value = NULL;
|
||||
enum {
|
||||
KEY_START = 0,
|
||||
KEY,
|
||||
VALUE_START,
|
||||
VALUE,
|
||||
VALUE_QUOTED
|
||||
} state = 0;
|
||||
|
||||
for (p = cmdline; *p; p++) {
|
||||
switch (state) {
|
||||
case KEY_START: /* looking for the start of a key */
|
||||
if (*p == ' ') continue;
|
||||
key = p;
|
||||
state = KEY;
|
||||
break;
|
||||
|
||||
case KEY: /* reading key */
|
||||
if (*p == ' ') {
|
||||
add_string (&ret, &len, key, p-key);
|
||||
add_string (&ret, &len, "", 0);
|
||||
state = KEY_START;
|
||||
}
|
||||
else if (*p == '=') {
|
||||
add_string (&ret, &len, key, p-key);
|
||||
state = VALUE_START;
|
||||
}
|
||||
break;
|
||||
|
||||
case VALUE_START: /* looking for the start of a value */
|
||||
if (*p == ' ') {
|
||||
add_string (&ret, &len, "", 0);
|
||||
state = KEY_START;
|
||||
}
|
||||
else if (*p == '"') {
|
||||
value = p+1;
|
||||
state = VALUE_QUOTED;
|
||||
}
|
||||
else {
|
||||
value = p;
|
||||
state = VALUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case VALUE: /* reading unquoted value */
|
||||
if (*p == ' ') {
|
||||
add_string (&ret, &len, value, p-value);
|
||||
state = KEY_START;
|
||||
}
|
||||
break;
|
||||
|
||||
case VALUE_QUOTED: /* reading quoted value */
|
||||
if (*p == '"') {
|
||||
add_string (&ret, &len, value, p-value);
|
||||
state = KEY_START;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case KEY_START: break;
|
||||
case KEY: /* key followed by end of string */
|
||||
add_string (&ret, &len, key, p-key);
|
||||
add_string (&ret, &len, "", 0);
|
||||
break;
|
||||
case VALUE_START: /* key= followed by end of string */
|
||||
add_string (&ret, &len, "", 0);
|
||||
break;
|
||||
case VALUE: /* key=value followed by end of string */
|
||||
add_string (&ret, &len, value, p-value);
|
||||
break;
|
||||
case VALUE_QUOTED: /* unterminated key="value" */
|
||||
fprintf (stderr, "%s: warning: unterminated quoted string on kernel command line\n",
|
||||
getprogname ());
|
||||
add_string (&ret, &len, value, p-value);
|
||||
}
|
||||
|
||||
add_null (&ret, &len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char **
|
||||
parse_proc_cmdline (void)
|
||||
{
|
||||
CLEANUP_FCLOSE FILE *fp = NULL;
|
||||
CLEANUP_FREE char *cmdline = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
fp = fopen ("/proc/cmdline", "re");
|
||||
if (fp == NULL) {
|
||||
perror ("/proc/cmdline");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (getline (&cmdline, &len, fp) == -1) {
|
||||
perror ("getline");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 'len' is not the length of the string, but the length of the
|
||||
* buffer. We need to chomp the string.
|
||||
*/
|
||||
len = strlen (cmdline);
|
||||
|
||||
if (len >= 1 && cmdline[len-1] == '\n')
|
||||
cmdline[len-1] = '\0';
|
||||
|
||||
return parse_cmdline_string (cmdline);
|
||||
}
|
||||
|
||||
const char *
|
||||
get_cmdline_key (char **argv, const char *key)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; argv[i] != NULL; i += 2) {
|
||||
if (STREQ (argv[i], key))
|
||||
return argv[i+1];
|
||||
}
|
||||
|
||||
/* Not found. */
|
||||
return NULL;
|
||||
}
|
||||
158
p2v/kernel.c
158
p2v/kernel.c
@@ -1,158 +0,0 @@
|
||||
/* virt-p2v
|
||||
* Copyright (C) 2009-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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Kernel-driven, non-interactive configuration of virt-p2v.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <assert.h>
|
||||
#include <locale.h>
|
||||
#include <libintl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "getprogname.h"
|
||||
|
||||
#include "p2v.h"
|
||||
|
||||
static void notify_ui_callback (int type, const char *data);
|
||||
static void run_command (const char *stage, const char *command);
|
||||
|
||||
/* Perform conversion using the kernel method. */
|
||||
void
|
||||
kernel_conversion (struct config *config, char **cmdline, int cmdline_source)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
/* Pre-conversion command. */
|
||||
p = get_cmdline_key (cmdline, "p2v.pre");
|
||||
if (p)
|
||||
run_command ("p2v.pre", p);
|
||||
|
||||
/* Connect to and interrogate virt-v2v on the conversion server. */
|
||||
p = get_cmdline_key (cmdline, "p2v.skip_test_connection");
|
||||
if (!p) {
|
||||
wait_network_online (config);
|
||||
if (test_connection (config) == -1) {
|
||||
const char *err = get_ssh_error ();
|
||||
|
||||
error (EXIT_FAILURE, 0,
|
||||
"error opening control connection to %s:%d: %s",
|
||||
config->remote.server, config->remote.port, err);
|
||||
}
|
||||
}
|
||||
|
||||
/* Some disks must have been specified for conversion. */
|
||||
if (config->disks == NULL || guestfs_int_count_strings (config->disks) == 0)
|
||||
error (EXIT_FAILURE, 0,
|
||||
"no non-removable disks were discovered on this machine.\n"
|
||||
"virt-p2v looked in /sys/block and in p2v.disks on the kernel command line.\n"
|
||||
"This is a fatal error and virt-p2v cannot continue.");
|
||||
|
||||
/* Perform the conversion in text mode. */
|
||||
if (start_conversion (config, notify_ui_callback) == -1) {
|
||||
const char *err = get_conversion_error ();
|
||||
|
||||
fprintf (stderr, "%s: error during conversion: %s\n",
|
||||
getprogname (), err);
|
||||
|
||||
p = get_cmdline_key (cmdline, "p2v.fail");
|
||||
if (p)
|
||||
run_command ("p2v.fail", p);
|
||||
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ansi_green (stdout);
|
||||
printf ("Conversion finished successfully.");
|
||||
ansi_restore (stdout);
|
||||
putchar ('\n');
|
||||
|
||||
p = get_cmdline_key (cmdline, "p2v.post");
|
||||
if (!p) {
|
||||
if (geteuid () == 0 && cmdline_source == CMDLINE_SOURCE_PROC_CMDLINE)
|
||||
p = "poweroff";
|
||||
}
|
||||
if (p)
|
||||
run_command ("p2v.post", p);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_ui_callback (int type, const char *data)
|
||||
{
|
||||
switch (type) {
|
||||
case NOTIFY_LOG_DIR:
|
||||
ansi_magenta (stdout);
|
||||
printf ("%s: remote log directory location: ", getprogname ());
|
||||
ansi_red (stdout);
|
||||
fputs (data, stdout);
|
||||
ansi_restore (stdout);
|
||||
putchar ('\n');
|
||||
break;
|
||||
|
||||
case NOTIFY_REMOTE_MESSAGE:
|
||||
printf ("%s", data);
|
||||
break;
|
||||
|
||||
case NOTIFY_STATUS:
|
||||
ansi_magenta (stdout);
|
||||
printf ("%s: %s", getprogname (), data);
|
||||
ansi_restore (stdout);
|
||||
putchar ('\n');
|
||||
break;
|
||||
|
||||
default:
|
||||
ansi_red (stdout);
|
||||
printf ("%s: unknown message during conversion: type=%d data=%s",
|
||||
getprogname (), type, data);
|
||||
ansi_restore (stdout);
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
fflush (stdout);
|
||||
}
|
||||
|
||||
static void
|
||||
run_command (const char *stage, const char *command)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (STREQ (command, ""))
|
||||
return;
|
||||
|
||||
#if DEBUG_STDERR
|
||||
fprintf (stderr, "%s\n", command);
|
||||
fflush (stderr);
|
||||
#endif
|
||||
|
||||
r = system (command);
|
||||
if (r == -1)
|
||||
error (EXIT_FAILURE, errno, "system: %s", command);
|
||||
if ((WIFEXITED (r) && WEXITSTATUS (r) != 0) || !WIFEXITED (r))
|
||||
error (EXIT_FAILURE, 0,
|
||||
"%s: unexpected failure of external command", stage);
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
#!/bin/bash
|
||||
#================
|
||||
# FILE : config.sh
|
||||
#----------------
|
||||
# PROJECT : OpenSuSE KIWI Image System
|
||||
# COPYRIGHT : (c) 2006 SUSE LINUX Products GmbH. All rights reserved
|
||||
# :
|
||||
# AUTHOR : Marcus Schaefer <ms@suse.de>
|
||||
#======================================
|
||||
# Functions...
|
||||
#--------------------------------------
|
||||
test -f /.kconfig && . /.kconfig
|
||||
test -f /.profile && . /.profile
|
||||
|
||||
#======================================
|
||||
# Greeting...
|
||||
#--------------------------------------
|
||||
echo "Configure image: [$kiwi_iname]..."
|
||||
|
||||
#======================================
|
||||
# Mount system filesystems
|
||||
#--------------------------------------
|
||||
baseMount
|
||||
|
||||
#======================================
|
||||
# Setup baseproduct link
|
||||
#--------------------------------------
|
||||
suseSetupProduct
|
||||
|
||||
#======================================
|
||||
# Add missing gpg keys to rpm
|
||||
#--------------------------------------
|
||||
suseImportBuildKey
|
||||
|
||||
#======================================
|
||||
# Activate services
|
||||
#--------------------------------------
|
||||
suseInsertService p2v
|
||||
|
||||
#======================================
|
||||
# Setup default target, multi-user
|
||||
#--------------------------------------
|
||||
baseSetRunlevel 3
|
||||
|
||||
#==========================================
|
||||
# remove package docs
|
||||
#------------------------------------------
|
||||
rm -rf /usr/share/doc/packages/*
|
||||
rm -rf /usr/share/doc/manual/*
|
||||
rm -rf /opt/kde*
|
||||
|
||||
# Update the default getty target to login automatically as root without
|
||||
# prompting for a password
|
||||
sed -i 's/^ExecStart=\(.*\)/ExecStart=\1 -a root/' \
|
||||
/usr/lib/systemd/system/getty@.service
|
||||
|
||||
# Reserve tty1 as a getty so we can document it clearly
|
||||
echo ReserveVT=1 >> /etc/systemd/logind.conf
|
||||
|
||||
sed -i 's/^ROOT_USES_LANG=.*$/ROOT_USES_LANG="yes"/' \
|
||||
/etc/sysconfig/language
|
||||
|
||||
#======================================
|
||||
# SuSEconfig
|
||||
#--------------------------------------
|
||||
suseConfig
|
||||
|
||||
#======================================
|
||||
# Umount kernel filesystems
|
||||
#--------------------------------------
|
||||
baseCleanMount
|
||||
|
||||
exit 0
|
||||
@@ -1,92 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<image schemaversion="6.2" name="p2v-__KIWI_BOOT__" displayname="p2v___PACKAGE_VERSION_____KIWI_BOOT__">
|
||||
<description type="system">
|
||||
<author>Marcus Schäfer</author>
|
||||
<contact>ms@suse.com</contact>
|
||||
<specification>P2V __PACKAGE_VERSION__</specification>
|
||||
</description>
|
||||
<profiles>
|
||||
<profile name="vmxFlavour" description="VMX with default kernel" import="true"/>
|
||||
<profile name="netboot" description="compressed rootfs image for pxe"/>
|
||||
</profiles>
|
||||
<preferences>
|
||||
<type image="iso" primary="true" boot="isoboot/suse-__KIWI_BOOT__" flags="overlay" hybrid="true" firmware="uefi" kernelcmdline="splash"/>
|
||||
<version>__PACKAGE_VERSION__</version>
|
||||
<packagemanager>zypper</packagemanager>
|
||||
<locale>en_US</locale>
|
||||
<keytable>us.map.gz</keytable>
|
||||
<hwclock>utc</hwclock>
|
||||
<bootloader-theme>__BRANDING__</bootloader-theme>
|
||||
<bootsplash-theme>__BRANDING__</bootsplash-theme>
|
||||
<rpm-excludedocs>true</rpm-excludedocs>
|
||||
<rpm-check-signatures>false</rpm-check-signatures>
|
||||
</preferences>
|
||||
<preferences profiles="netboot">
|
||||
<type image="pxe" filesystem="overlayfs" boot="netboot/suse-__KIWI_BOOT__">
|
||||
<pxedeploy server="192.168.100.2" blocksize="4096">
|
||||
<partitions device="/dev/sda">
|
||||
<partition type="swap" number="1" size="5"/>
|
||||
<partition type="L" number="2" size="image" mountpoint="/" target="true"/>
|
||||
<partition type="L" number="3" target="false"/>
|
||||
</partitions>
|
||||
<union ro="/dev/sda2" rw="/dev/sda3" type="overlayfs"/>
|
||||
</pxedeploy>
|
||||
</type>
|
||||
</preferences>
|
||||
<preferences profiles="vmxFlavour">
|
||||
<type image="vmx" filesystem="ext3" boot="vmxboot/suse-__KIWI_BOOT__" format="vmdk" bootloader="grub2" firmware="uefi" kernelcmdline="splash" bootpartition="false">
|
||||
<systemdisk name="systemVG"/>
|
||||
<machine memory="512" guestOS="suse" HWversion="4">
|
||||
<vmdisk id="0" controller="ide"/>
|
||||
<vmnic driver="e1000" interface="0" mode="bridged"/>
|
||||
</machine>
|
||||
</type>
|
||||
</preferences>
|
||||
<users group="root">
|
||||
<user password="p2v" pwdformat="plain" home="/root" name="root"/>
|
||||
</users>
|
||||
<!--__REPOS__-->
|
||||
<packages type="image" patternType="onlyRequired">
|
||||
<package name="__BASE_PATTERN__"/>
|
||||
<package name="plymouth-branding-__BRANDING__" bootinclude="true"/>
|
||||
<package name="grub2-branding-__BRANDING__" bootinclude="true"/>
|
||||
<package name="iputils"/>
|
||||
<package name="grub2"/>
|
||||
<package name="grub2-x86_64-efi"/>
|
||||
<package name="syslinux"/>
|
||||
<package name="lvm2"/>
|
||||
<package name="plymouth"/>
|
||||
<package name="fontconfig"/>
|
||||
<package name="fonts-config"/>
|
||||
<package name="tar"/>
|
||||
<package name="systemd"/>
|
||||
<package name="systemd-sysvinit"/>
|
||||
<package name="dracut"/>
|
||||
<package name="wicked"/>
|
||||
<package name="iproute2"/>
|
||||
<package name="sudo"/>
|
||||
<package name="dhcp-client"/>
|
||||
<package name="which"/>
|
||||
<!-- virt-p2v dependencies from dependencies.suse -->
|
||||
<!--__DEPENDENCIES__-->
|
||||
</packages>
|
||||
<packages type="iso">
|
||||
<package name="gfxboot-branding-__BRANDING__" bootinclude="true" bootdelete="true"/>
|
||||
</packages>
|
||||
<packages type="image" profiles="vmxFlavour">
|
||||
<package name="kernel-default" replaces="kernel-xen"/>
|
||||
<package name="kernel-default" replaces="xen-kmp-default"/>
|
||||
<package name="kernel-default" replaces="xen-libs"/>
|
||||
<package name="kernel-default" replaces="xen-tools"/>
|
||||
<package name="kernel-default" replaces="xen"/>
|
||||
<package name="gfxboot-branding-__BRANDING__" bootinclude="true" bootdelete="true"/>
|
||||
</packages>
|
||||
<packages type="bootstrap">
|
||||
<package name="udev"/>
|
||||
<package name="filesystem"/>
|
||||
<package name="glibc-locale"/>
|
||||
<package name="cracklib-dict-full"/>
|
||||
<package name="ca-certificates"/>
|
||||
<package name="__RELEASE_PKG__"/>
|
||||
</packages>
|
||||
</image>
|
||||
@@ -1,51 +0,0 @@
|
||||
#!/bin/bash -
|
||||
# (C) Copyright 2014-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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
# This normally runs from systemd which deals with logging.
|
||||
|
||||
# Are we running in GUI or non-GUI mode? This is controlled by the
|
||||
# presence of "p2v.server" on the kernel command line.
|
||||
cmdline=$(</proc/cmdline)
|
||||
if [[ $cmdline == *p2v.server=* ]]; then
|
||||
# Non-GUI mode, don't run X. Just run virt-p2v directly.
|
||||
exec /usr/bin/virt-p2v --iso --colours
|
||||
|
||||
else
|
||||
# GUI mode. Run xinit to start X. To save one script, we invoke
|
||||
# self again to run the window manager and virt-p2v.
|
||||
if [ "$1" = "run" ]; then
|
||||
cd /
|
||||
|
||||
ID=
|
||||
if test -f /etc/os-release; then
|
||||
. /etc/os-release
|
||||
fi
|
||||
|
||||
case "$ID" in
|
||||
sles|opensuse)
|
||||
# not all versions of SLE / openSUSE ship metacity and nm-applet
|
||||
icewm &
|
||||
;;
|
||||
*)
|
||||
metacity &
|
||||
nm-applet &
|
||||
esac
|
||||
exec /usr/bin/virt-p2v --iso --colours
|
||||
else
|
||||
xinit "$0" run
|
||||
fi
|
||||
fi
|
||||
583
p2v/main.c
583
p2v/main.c
@@ -1,583 +0,0 @@
|
||||
/* virt-p2v
|
||||
* Copyright (C) 2009-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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <dirent.h>
|
||||
#include <locale.h>
|
||||
#include <libintl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if MAJOR_IN_MKDEV
|
||||
#include <sys/mkdev.h>
|
||||
#elif MAJOR_IN_SYSMACROS
|
||||
#include <sys/sysmacros.h>
|
||||
/* else it's in sys/types.h, included above */
|
||||
#endif
|
||||
|
||||
/* errors in <gtk.h> */
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
|
||||
#if defined(__GNUC__) && __GNUC__ >= 6 /* gcc >= 6 */
|
||||
#pragma GCC diagnostic ignored "-Wshift-overflow"
|
||||
#endif
|
||||
#include <gtk/gtk.h>
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#include "ignore-value.h"
|
||||
#include "getprogname.h"
|
||||
#include "p2v.h"
|
||||
|
||||
char **all_disks;
|
||||
char **all_removable;
|
||||
char **all_interfaces;
|
||||
int is_iso_environment = 0;
|
||||
int feature_colours_option = 0;
|
||||
int force_colour = 0;
|
||||
static const char *test_disk = NULL;
|
||||
|
||||
static void udevadm_settle (void);
|
||||
static void set_config_defaults (struct config *config);
|
||||
static void find_all_disks (void);
|
||||
static void find_all_interfaces (void);
|
||||
|
||||
enum { HELP_OPTION = CHAR_MAX + 1 };
|
||||
static const char options[] = "Vv";
|
||||
static const struct option long_options[] = {
|
||||
{ "help", 0, 0, HELP_OPTION },
|
||||
{ "cmdline", 1, 0, 0 },
|
||||
{ "color", 0, 0, 0 },
|
||||
{ "colors", 0, 0, 0 },
|
||||
{ "colour", 0, 0, 0 },
|
||||
{ "colours", 0, 0, 0 },
|
||||
{ "iso", 0, 0, 0 },
|
||||
{ "nbd", 1, 0, 0 },
|
||||
{ "long-options", 0, 0, 0 },
|
||||
{ "short-options", 0, 0, 0 },
|
||||
{ "test-disk", 1, 0, 0 },
|
||||
{ "verbose", 0, 0, 'v' },
|
||||
{ "version", 0, 0, 'V' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
static void __attribute__((noreturn))
|
||||
usage (int status)
|
||||
{
|
||||
if (status != EXIT_SUCCESS)
|
||||
fprintf (stderr, _("Try ‘%s --help’ for more information.\n"),
|
||||
getprogname ());
|
||||
else {
|
||||
printf (_("%s: Convert a physical machine to use KVM\n"
|
||||
"Copyright (C) 2009-2019 Red Hat Inc.\n"
|
||||
"Usage:\n"
|
||||
" %s [--options]\n"
|
||||
"Options:\n"
|
||||
" --help Display brief help\n"
|
||||
" --cmdline=CMDLINE Used to debug command line parsing\n"
|
||||
" --colors|--colours Use ANSI colour sequences even if not tty\n"
|
||||
" --iso Running in the ISO environment\n"
|
||||
" --nbd=qemu-nbd,nbdkit Search order for NBD servers\n"
|
||||
" --test-disk=DISK.IMG For testing, use disk as /dev/sda\n"
|
||||
" -v|--verbose Verbose messages\n"
|
||||
" -V|--version Display version and exit\n"
|
||||
"For more information, see the manpage %s(1).\n"),
|
||||
getprogname (), getprogname (),
|
||||
getprogname ());
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
|
||||
/* XXX Copied from fish/options.c. */
|
||||
static void
|
||||
display_short_options (const char *format)
|
||||
{
|
||||
while (*format) {
|
||||
if (*format != ':')
|
||||
printf ("-%c\n", *format);
|
||||
++format;
|
||||
}
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static void
|
||||
display_long_options (const struct option *long_options)
|
||||
{
|
||||
while (long_options->name) {
|
||||
if (STRNEQ (long_options->name, "long-options") && STRNEQ (long_options->name, "short-options"))
|
||||
printf ("--%s\n", long_options->name);
|
||||
long_options++;
|
||||
}
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
gboolean gui_possible;
|
||||
int c;
|
||||
int option_index;
|
||||
char **cmdline = NULL;
|
||||
int cmdline_source = 0;
|
||||
struct config *config = new_config ();
|
||||
|
||||
setlocale (LC_ALL, "");
|
||||
bindtextdomain (PACKAGE, LOCALEBASEDIR);
|
||||
textdomain (PACKAGE);
|
||||
|
||||
/* We may use random(3) in this program. */
|
||||
srandom (time (NULL) + getpid ());
|
||||
|
||||
/* There is some raciness between slow devices being discovered by
|
||||
* the kernel and udev and virt-p2v running. This is a partial
|
||||
* workaround, but a real fix involves handling hotplug events
|
||||
* (possible in GUI mode, not easy in kernel mode).
|
||||
*/
|
||||
udevadm_settle ();
|
||||
|
||||
gui_possible = gtk_init_check (&argc, &argv);
|
||||
|
||||
for (;;) {
|
||||
c = getopt_long (argc, argv, options, long_options, &option_index);
|
||||
if (c == -1) break;
|
||||
|
||||
switch (c) {
|
||||
case 0: /* options which are long only */
|
||||
if (STREQ (long_options[option_index].name, "long-options")) {
|
||||
display_long_options (long_options);
|
||||
}
|
||||
else if (STREQ (long_options[option_index].name, "short-options")) {
|
||||
display_short_options (options);
|
||||
}
|
||||
else if (STREQ (long_options[option_index].name, "cmdline")) {
|
||||
cmdline = parse_cmdline_string (optarg);
|
||||
cmdline_source = CMDLINE_SOURCE_COMMAND_LINE;
|
||||
}
|
||||
else if (STREQ (long_options[option_index].name, "color") ||
|
||||
STREQ (long_options[option_index].name, "colour") ||
|
||||
STREQ (long_options[option_index].name, "colors") ||
|
||||
STREQ (long_options[option_index].name, "colours")) {
|
||||
force_colour = 1;
|
||||
}
|
||||
else if (STREQ (long_options[option_index].name, "iso")) {
|
||||
is_iso_environment = 1;
|
||||
}
|
||||
else if (STREQ (long_options[option_index].name, "nbd")) {
|
||||
set_nbd_option (optarg); /* in nbd.c */
|
||||
}
|
||||
else if (STREQ (long_options[option_index].name, "test-disk")) {
|
||||
if (test_disk != NULL)
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("only a single --test-disk option can be used"));
|
||||
if (optarg[0] != '/')
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("--test-disk must be an absolute path"));
|
||||
test_disk = optarg;
|
||||
}
|
||||
else
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("unknown long option: %s (%d)"),
|
||||
long_options[option_index].name, option_index);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
/* This option does nothing since 1.33.41. Verbose is always
|
||||
* enabled.
|
||||
*/
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
printf ("%s %s\n", getprogname (), PACKAGE_VERSION_FULL);
|
||||
exit (EXIT_SUCCESS);
|
||||
|
||||
case HELP_OPTION:
|
||||
usage (EXIT_SUCCESS);
|
||||
|
||||
default:
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind != argc) {
|
||||
fprintf (stderr, _("%s: unused arguments on the command line\n"),
|
||||
getprogname ());
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
test_nbd_servers ();
|
||||
|
||||
set_config_defaults (config);
|
||||
|
||||
/* Parse /proc/cmdline (if it exists) or use the --cmdline parameter
|
||||
* to initialize the configuration. This allows defaults to be pass
|
||||
* using the kernel command line, with additional GUI configuration
|
||||
* later.
|
||||
*/
|
||||
if (cmdline == NULL) {
|
||||
cmdline = parse_proc_cmdline ();
|
||||
if (cmdline != NULL)
|
||||
cmdline_source = CMDLINE_SOURCE_PROC_CMDLINE;
|
||||
}
|
||||
|
||||
if (cmdline)
|
||||
update_config_from_kernel_cmdline (config, cmdline);
|
||||
|
||||
/* If p2v.server exists, then we use the non-interactive kernel
|
||||
* conversion. Otherwise we run the GUI.
|
||||
*/
|
||||
if (config->remote.server != NULL)
|
||||
kernel_conversion (config, cmdline, cmdline_source);
|
||||
else {
|
||||
if (!gui_possible)
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("gtk_init_check returned false, indicating that\n"
|
||||
"a GUI is not possible on this host. Check X11, $DISPLAY etc."));
|
||||
gui_conversion (config);
|
||||
}
|
||||
|
||||
guestfs_int_free_string_list (cmdline);
|
||||
free_config (config);
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static void
|
||||
udevadm_settle (void)
|
||||
{
|
||||
ignore_value (system ("udevadm settle"));
|
||||
}
|
||||
|
||||
static void
|
||||
set_config_defaults (struct config *config)
|
||||
{
|
||||
long i;
|
||||
char hostname[257];
|
||||
|
||||
/* Default guest name is derived from the source hostname. If we
|
||||
* assume that the p2v ISO gets its IP address and hostname from
|
||||
* DHCP, then there is at better than average chance that
|
||||
* gethostname will return the real hostname here. It's better than
|
||||
* trying to fish around in the guest filesystem anyway.
|
||||
*/
|
||||
if (gethostname (hostname, sizeof hostname) == -1) {
|
||||
perror ("gethostname");
|
||||
/* Generate a simple random name. */
|
||||
if (guestfs_int_random_string (hostname, 8) == -1)
|
||||
error (EXIT_FAILURE, errno, "guestfs_int_random_string");
|
||||
} else {
|
||||
char *p;
|
||||
|
||||
/* If the hostname is an FQDN, truncate before the first dot. */
|
||||
p = strchr (hostname, '.');
|
||||
if (p && p > hostname)
|
||||
*p = '\0';
|
||||
}
|
||||
config->guestname = strdup (hostname);
|
||||
|
||||
/* Defaults for #vcpus and memory are taken from the physical machine. */
|
||||
i = sysconf (_SC_NPROCESSORS_ONLN);
|
||||
if (i == -1) {
|
||||
perror ("sysconf: _SC_NPROCESSORS_ONLN");
|
||||
config->vcpus = 1;
|
||||
}
|
||||
else if (i == 0)
|
||||
config->vcpus = 1;
|
||||
else
|
||||
config->vcpus = i;
|
||||
|
||||
i = sysconf (_SC_PHYS_PAGES);
|
||||
if (i == -1) {
|
||||
perror ("sysconf: _SC_PHYS_PAGES");
|
||||
config->memory = 1024 * 1024 * 1024;
|
||||
}
|
||||
else
|
||||
config->memory = i;
|
||||
|
||||
i = sysconf (_SC_PAGESIZE);
|
||||
if (i == -1) {
|
||||
perror ("sysconf: _SC_PAGESIZE");
|
||||
config->memory *= 4096;
|
||||
}
|
||||
else
|
||||
config->memory *= i;
|
||||
|
||||
/* Round up the default memory to a power of 2, since the kernel
|
||||
* memory is not included in the total physical pages returned
|
||||
* above.
|
||||
* http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
||||
*/
|
||||
config->memory--;
|
||||
config->memory |= config->memory >> 1;
|
||||
config->memory |= config->memory >> 2;
|
||||
config->memory |= config->memory >> 4;
|
||||
config->memory |= config->memory >> 8;
|
||||
config->memory |= config->memory >> 16;
|
||||
config->memory |= config->memory >> 32;
|
||||
config->memory++;
|
||||
|
||||
get_cpu_config (&config->cpu);
|
||||
get_rtc_config (&config->rtc);
|
||||
|
||||
/* Find all block devices in the system. */
|
||||
if (!test_disk)
|
||||
find_all_disks ();
|
||||
else {
|
||||
/* For testing and debugging purposes, you can use
|
||||
* --test-disk=/path/to/disk.img
|
||||
*/
|
||||
all_disks = malloc (2 * sizeof (char *));
|
||||
if (all_disks == NULL)
|
||||
error (EXIT_FAILURE, errno, "realloc");
|
||||
all_disks[0] = strdup (test_disk);
|
||||
if (all_disks[0] == NULL)
|
||||
error (EXIT_FAILURE, errno, "strdup");
|
||||
all_disks[1] = NULL;
|
||||
}
|
||||
if (all_disks)
|
||||
config->disks = guestfs_int_copy_string_list (all_disks);
|
||||
|
||||
/* Find all removable devices in the system. */
|
||||
if (all_removable)
|
||||
config->removable = guestfs_int_copy_string_list (all_removable);
|
||||
|
||||
/* Find all network interfaces in the system. */
|
||||
find_all_interfaces ();
|
||||
if (all_interfaces)
|
||||
config->interfaces = guestfs_int_copy_string_list (all_interfaces);
|
||||
|
||||
/* Default output drops the guest onto /var/tmp on the conversion
|
||||
* server, a hopefully safe default.
|
||||
*/
|
||||
config->output.type = strdup ("local");
|
||||
config->output.storage = strdup ("/var/tmp");
|
||||
}
|
||||
|
||||
static int
|
||||
compare (const void *vp1, const void *vp2)
|
||||
{
|
||||
char * const *p1 = (char * const *) vp1;
|
||||
char * const *p2 = (char * const *) vp2;
|
||||
return strcmp (*p1, *p2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get parent device of a partition.
|
||||
*
|
||||
* Returns C<0> if no parent device could be found.
|
||||
*/
|
||||
static dev_t
|
||||
partition_parent (dev_t part_dev)
|
||||
{
|
||||
CLEANUP_FCLOSE FILE *fp = NULL;
|
||||
CLEANUP_FREE char *path = NULL, *content = NULL;
|
||||
size_t len = 0;
|
||||
unsigned parent_major, parent_minor;
|
||||
|
||||
if (asprintf (&path, "/sys/dev/block/%ju:%ju/../dev",
|
||||
(uintmax_t) major (part_dev),
|
||||
(uintmax_t) minor (part_dev)) == -1)
|
||||
error (EXIT_FAILURE, errno, "asprintf");
|
||||
|
||||
fp = fopen (path, "r");
|
||||
if (fp == NULL)
|
||||
return 0;
|
||||
|
||||
if (getline (&content, &len, fp) == -1)
|
||||
error (EXIT_FAILURE, errno, "getline");
|
||||
|
||||
if (sscanf (content, "%u:%u", &parent_major, &parent_minor) != 2)
|
||||
return 0;
|
||||
|
||||
return makedev (parent_major, parent_minor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the named device (eg. C<dev == "sda">) contains the
|
||||
* root filesystem. C<root_device> is the major:minor of the root
|
||||
* filesystem (eg. C<8:1> if the root filesystem was F</dev/sda1>).
|
||||
*
|
||||
* This doesn't work for LVs and so on. However we only really care
|
||||
* if this test works on the P2V ISO where the root device is a
|
||||
* regular partition.
|
||||
*/
|
||||
static int
|
||||
device_contains (const char *dev, dev_t root_device)
|
||||
{
|
||||
struct stat statbuf;
|
||||
CLEANUP_FREE char *dev_name = NULL;
|
||||
dev_t root_device_parent;
|
||||
|
||||
if (asprintf (&dev_name, "/dev/%s", dev) == -1)
|
||||
error (EXIT_FAILURE, errno, "asprintf");
|
||||
|
||||
if (stat (dev_name, &statbuf) == -1)
|
||||
return 0;
|
||||
|
||||
/* See if dev is the root_device. */
|
||||
if (statbuf.st_rdev == root_device)
|
||||
return 1;
|
||||
|
||||
/* See if dev is the parent device of the root_device. */
|
||||
root_device_parent = partition_parent (root_device);
|
||||
if (root_device_parent == 0)
|
||||
return 0;
|
||||
if (statbuf.st_rdev == root_device_parent)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerate all disks in F</sys/block> and add them to the global
|
||||
* C<all_disks> and C<all_removable> arrays.
|
||||
*/
|
||||
static void
|
||||
find_all_disks (void)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *d;
|
||||
size_t nr_disks = 0, nr_removable = 0;
|
||||
dev_t root_device = 0;
|
||||
struct stat statbuf;
|
||||
|
||||
if (stat ("/", &statbuf) == 0)
|
||||
root_device = statbuf.st_dev;
|
||||
|
||||
/* The default list of disks is everything in /sys/block which
|
||||
* matches the common patterns for disk names.
|
||||
*/
|
||||
dir = opendir ("/sys/block");
|
||||
if (!dir)
|
||||
error (EXIT_FAILURE, errno, "opendir");
|
||||
|
||||
for (;;) {
|
||||
errno = 0;
|
||||
d = readdir (dir);
|
||||
if (!d) break;
|
||||
|
||||
if (STRPREFIX (d->d_name, "cciss!") ||
|
||||
STRPREFIX (d->d_name, "hd") ||
|
||||
STRPREFIX (d->d_name, "sd") ||
|
||||
STRPREFIX (d->d_name, "ubd") ||
|
||||
STRPREFIX (d->d_name, "vd")) {
|
||||
char *p;
|
||||
|
||||
/* Skip the device containing the root filesystem. */
|
||||
if (device_contains (d->d_name, root_device))
|
||||
continue;
|
||||
|
||||
nr_disks++;
|
||||
all_disks = realloc (all_disks, sizeof (char *) * (nr_disks + 1));
|
||||
if (!all_disks)
|
||||
error (EXIT_FAILURE, errno, "realloc");
|
||||
|
||||
all_disks[nr_disks-1] = strdup (d->d_name);
|
||||
|
||||
/* cciss device /dev/cciss/c0d0 will be /sys/block/cciss!c0d0 */
|
||||
p = strchr (all_disks[nr_disks-1], '!');
|
||||
if (p) *p = '/';
|
||||
|
||||
all_disks[nr_disks] = NULL;
|
||||
}
|
||||
else if (STRPREFIX (d->d_name, "sr")) {
|
||||
nr_removable++;
|
||||
all_removable = realloc (all_removable,
|
||||
sizeof (char *) * (nr_removable + 1));
|
||||
if (!all_removable)
|
||||
error (EXIT_FAILURE, errno, "realloc");
|
||||
all_removable[nr_removable-1] = strdup (d->d_name);
|
||||
all_removable[nr_removable] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check readdir didn't fail */
|
||||
if (errno != 0)
|
||||
error (EXIT_FAILURE, errno, "readdir: %s", "/sys/block");
|
||||
|
||||
/* Close the directory handle */
|
||||
if (closedir (dir) == -1)
|
||||
error (EXIT_FAILURE, errno, "closedir: %s", "/sys/block");
|
||||
|
||||
if (all_disks)
|
||||
qsort (all_disks, nr_disks, sizeof (char *), compare);
|
||||
if (all_removable)
|
||||
qsort (all_removable, nr_removable, sizeof (char *), compare);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerate all network interfaces in F</sys/class/net> and add them
|
||||
* to the global C<all_interfaces> array.
|
||||
*/
|
||||
static void
|
||||
find_all_interfaces (void)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *d;
|
||||
size_t nr_interfaces = 0;
|
||||
|
||||
/* The default list of network interfaces is everything in
|
||||
* /sys/class/net which matches some common patterns.
|
||||
*/
|
||||
dir = opendir ("/sys/class/net");
|
||||
if (!dir)
|
||||
error (EXIT_FAILURE, errno, "opendir: %s", "/sys/class/net");
|
||||
|
||||
for (;;) {
|
||||
errno = 0;
|
||||
d = readdir (dir);
|
||||
if (!d) break;
|
||||
|
||||
/* For systemd predictable names, see:
|
||||
* http://cgit.freedesktop.org/systemd/systemd/tree/src/udev/udev-builtin-net_id.c#n20
|
||||
* biosdevname is also a possibility here.
|
||||
* Ignore PPP, SLIP, WWAN, bridges, etc.
|
||||
*/
|
||||
if (STRPREFIX (d->d_name, "em") ||
|
||||
STRPREFIX (d->d_name, "en") ||
|
||||
STRPREFIX (d->d_name, "eth") ||
|
||||
STRPREFIX (d->d_name, "wl")) {
|
||||
nr_interfaces++;
|
||||
all_interfaces =
|
||||
realloc (all_interfaces, sizeof (char *) * (nr_interfaces + 1));
|
||||
if (!all_interfaces)
|
||||
error (EXIT_FAILURE, errno, "realloc");
|
||||
all_interfaces[nr_interfaces-1] = strdup (d->d_name);
|
||||
all_interfaces[nr_interfaces] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check readdir didn't fail */
|
||||
if (errno != 0)
|
||||
error (EXIT_FAILURE, errno, "readdir: %s", "/sys/class/net");
|
||||
|
||||
/* Close the directory handle */
|
||||
if (closedir (dir) == -1)
|
||||
error (EXIT_FAILURE, errno, "closedir: %s", "/sys/class/net");
|
||||
|
||||
if (all_interfaces)
|
||||
qsort (all_interfaces, nr_interfaces, sizeof (char *), compare);
|
||||
}
|
||||
840
p2v/nbd.c
840
p2v/nbd.c
@@ -1,840 +0,0 @@
|
||||
/* virt-p2v
|
||||
* Copyright (C) 2009-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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file handles the virt-p2v I<--nbd> command line option
|
||||
* and running either L<qemu-nbd(8)> or L<nbdkit(1)>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <libintl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "getprogname.h"
|
||||
|
||||
#include "p2v.h"
|
||||
|
||||
/* How long to wait for the NBD server to start (seconds). */
|
||||
#define WAIT_NBD_TIMEOUT 10
|
||||
|
||||
/* The local port that the NBD server listens on (incremented for
|
||||
* each server which is started).
|
||||
*/
|
||||
static int nbd_local_port;
|
||||
|
||||
/* List of servers specified by the --nbd option. */
|
||||
enum nbd_server {
|
||||
/* 0 is reserved for "end of list" */
|
||||
QEMU_NBD = 1,
|
||||
QEMU_NBD_NO_SA = 2,
|
||||
NBDKIT = 3,
|
||||
NBDKIT_NO_SA = 4,
|
||||
};
|
||||
static enum nbd_server *cmdline_servers = NULL;
|
||||
|
||||
static const char *
|
||||
nbd_server_string (enum nbd_server s)
|
||||
{
|
||||
const char *ret = NULL;
|
||||
|
||||
switch (s) {
|
||||
case QEMU_NBD: ret = "qemu-nbd"; break;
|
||||
case QEMU_NBD_NO_SA: ret = "qemu-nbd-no-sa"; break;
|
||||
case NBDKIT: ret = "nbdkit"; break;
|
||||
case NBDKIT_NO_SA: ret = "nbdkit-no-sa"; break;
|
||||
}
|
||||
|
||||
if (ret == NULL)
|
||||
abort ();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* If no --nbd option is passed, we use this standard list instead.
|
||||
* Must match the documentation in virt-p2v(1).
|
||||
*/
|
||||
static const enum nbd_server standard_servers[] =
|
||||
{ QEMU_NBD, QEMU_NBD_NO_SA, NBDKIT, NBDKIT_NO_SA, 0 };
|
||||
|
||||
/* After testing the list of servers passed by the user, this is
|
||||
* server we decide to use.
|
||||
*/
|
||||
static enum nbd_server use_server;
|
||||
|
||||
static pid_t start_qemu_nbd (const char *device, const char *ipaddr, int port, int *fds, size_t nr_fds);
|
||||
static pid_t start_nbdkit (const char *device, const char *ipaddr, int port, int *fds, size_t nr_fds);
|
||||
static int get_local_port (void);
|
||||
static int open_listening_socket (const char *ipaddr, int **fds, size_t *nr_fds);
|
||||
static int bind_tcpip_socket (const char *ipaddr, const char *port, int **fds, size_t *nr_fds);
|
||||
static int connect_with_source_port (const char *hostname, int dest_port, int source_port);
|
||||
static int bind_source_port (int sockfd, int family, int source_port);
|
||||
|
||||
static char *nbd_error;
|
||||
|
||||
static void set_nbd_error (const char *fs, ...)
|
||||
__attribute__((format(printf,1,2)));
|
||||
|
||||
static void
|
||||
set_nbd_error (const char *fs, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *msg;
|
||||
int len;
|
||||
|
||||
va_start (args, fs);
|
||||
len = vasprintf (&msg, fs, args);
|
||||
va_end (args);
|
||||
|
||||
if (len < 0)
|
||||
error (EXIT_FAILURE, errno,
|
||||
"vasprintf (original error format string: %s)", fs);
|
||||
|
||||
free (nbd_error);
|
||||
nbd_error = msg;
|
||||
}
|
||||
|
||||
const char *
|
||||
get_nbd_error (void)
|
||||
{
|
||||
return nbd_error;
|
||||
}
|
||||
|
||||
/**
|
||||
* The main program calls this to set the I<--nbd> option.
|
||||
*/
|
||||
void
|
||||
set_nbd_option (const char *opt)
|
||||
{
|
||||
size_t i, len;
|
||||
CLEANUP_FREE_STRING_LIST char **strs = NULL;
|
||||
|
||||
if (cmdline_servers != NULL)
|
||||
error (EXIT_FAILURE, 0, _("--nbd option appears multiple times"));
|
||||
|
||||
strs = guestfs_int_split_string (',', opt);
|
||||
|
||||
if (strs == NULL)
|
||||
error (EXIT_FAILURE, errno, _("malloc"));
|
||||
|
||||
len = guestfs_int_count_strings (strs);
|
||||
if (len == 0)
|
||||
error (EXIT_FAILURE, 0, _("--nbd option cannot be empty"));
|
||||
|
||||
cmdline_servers = malloc (sizeof (enum nbd_server) * (len + 1));
|
||||
if (cmdline_servers == NULL)
|
||||
error (EXIT_FAILURE, errno, _("malloc"));
|
||||
|
||||
for (i = 0; strs[i] != NULL; ++i) {
|
||||
if (STREQ (strs[i], "qemu-nbd") || STREQ (strs[i], "qemu"))
|
||||
cmdline_servers[i] = QEMU_NBD;
|
||||
else if (STREQ (strs[i], "qemu-nbd-no-sa") || STREQ (strs[i], "qemu-no-sa"))
|
||||
cmdline_servers[i] = QEMU_NBD_NO_SA;
|
||||
else if (STREQ (strs[i], "nbdkit"))
|
||||
cmdline_servers[i] = NBDKIT;
|
||||
else if (STREQ (strs[i], "nbdkit-no-sa"))
|
||||
cmdline_servers[i] = NBDKIT_NO_SA;
|
||||
else
|
||||
error (EXIT_FAILURE, 0, _("--nbd: unknown server: %s"), strs[i]);
|
||||
}
|
||||
|
||||
assert (i == len);
|
||||
cmdline_servers[i] = 0; /* marks the end of the list */
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the I<--nbd> option (or built-in default list) to see which
|
||||
* servers are actually installed and appear to be working.
|
||||
*
|
||||
* Set the C<use_server> global accordingly.
|
||||
*/
|
||||
void
|
||||
test_nbd_servers (void)
|
||||
{
|
||||
size_t i;
|
||||
int r;
|
||||
const enum nbd_server *servers;
|
||||
|
||||
/* Initialize nbd_local_port. */
|
||||
if (is_iso_environment)
|
||||
/* The p2v ISO should allow us to open up just about any port, so
|
||||
* we can fix a port number in that case. Using a predictable
|
||||
* port number in this case should avoid rare errors if the port
|
||||
* colides with another (ie. it'll either always fail or never
|
||||
* fail).
|
||||
*/
|
||||
nbd_local_port = 50123;
|
||||
else
|
||||
/* When testing on the local machine, choose a random port. */
|
||||
nbd_local_port = 50000 + (random () % 10000);
|
||||
|
||||
if (cmdline_servers != NULL)
|
||||
servers = cmdline_servers;
|
||||
else
|
||||
servers = standard_servers;
|
||||
|
||||
use_server = 0;
|
||||
|
||||
for (i = 0; servers[i] != 0; ++i) {
|
||||
#if DEBUG_STDERR
|
||||
fprintf (stderr, "checking for %s ...\n", nbd_server_string (servers[i]));
|
||||
#endif
|
||||
|
||||
switch (servers[i]) {
|
||||
case QEMU_NBD: /* with socket activation */
|
||||
r = system ("qemu-nbd --version"
|
||||
#ifndef DEBUG_STDERR
|
||||
" >/dev/null 2>&1"
|
||||
#endif
|
||||
" && grep -sq LISTEN_PID `which qemu-nbd`"
|
||||
);
|
||||
if (r == 0) {
|
||||
use_server = servers[i];
|
||||
goto finish;
|
||||
}
|
||||
break;
|
||||
|
||||
case QEMU_NBD_NO_SA:
|
||||
r = system ("qemu-nbd --version"
|
||||
#ifndef DEBUG_STDERR
|
||||
" >/dev/null 2>&1"
|
||||
#endif
|
||||
);
|
||||
if (r == 0) {
|
||||
use_server = servers[i];
|
||||
goto finish;
|
||||
}
|
||||
break;
|
||||
|
||||
case NBDKIT: /* with socket activation */
|
||||
r = system ("nbdkit file --version"
|
||||
#ifndef DEBUG_STDERR
|
||||
" >/dev/null 2>&1"
|
||||
#endif
|
||||
" && grep -sq LISTEN_PID `which nbdkit`"
|
||||
);
|
||||
if (r == 0) {
|
||||
use_server = servers[i];
|
||||
goto finish;
|
||||
}
|
||||
break;
|
||||
|
||||
case NBDKIT_NO_SA:
|
||||
r = system ("nbdkit file --version"
|
||||
#ifndef DEBUG_STDERR
|
||||
" >/dev/null 2>&1"
|
||||
#endif
|
||||
);
|
||||
if (r == 0) {
|
||||
use_server = servers[i];
|
||||
goto finish;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
if (use_server == 0) {
|
||||
fprintf (stderr,
|
||||
_("%s: no working NBD server was found, cannot continue.\n"
|
||||
"Please check the --nbd option in the virt-p2v(1) man page.\n"),
|
||||
getprogname ());
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Release memory used by the --nbd option. */
|
||||
free (cmdline_servers);
|
||||
cmdline_servers = NULL;
|
||||
|
||||
#if DEBUG_STDERR
|
||||
fprintf (stderr, "picked %s\n", nbd_server_string (use_server));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the NBD server.
|
||||
*
|
||||
* We previously tested all NBD servers (see C<test_nbd_servers>) and
|
||||
* hopefully found one which will work.
|
||||
*
|
||||
* Returns the process ID (E<gt> 0) or C<0> if there is an error.
|
||||
*/
|
||||
pid_t
|
||||
start_nbd_server (const char **ipaddr, int *port, const char *device)
|
||||
{
|
||||
int *fds = NULL;
|
||||
size_t i, nr_fds;
|
||||
pid_t pid;
|
||||
|
||||
switch (use_server) {
|
||||
case QEMU_NBD: /* qemu-nbd with socket activation */
|
||||
/* Ideally we would bind this socket to "localhost", but that
|
||||
* requires two listening FDs, and qemu-nbd currently cannot
|
||||
* support socket activation with two FDs. So we only bind to the
|
||||
* IPv4 address.
|
||||
*/
|
||||
*ipaddr = "127.0.0.1";
|
||||
*port = open_listening_socket (*ipaddr, &fds, &nr_fds);
|
||||
if (*port == -1) return -1;
|
||||
pid = start_qemu_nbd (device, *ipaddr, *port, fds, nr_fds);
|
||||
for (i = 0; i < nr_fds; ++i)
|
||||
close (fds[i]);
|
||||
free (fds);
|
||||
return pid;
|
||||
|
||||
case QEMU_NBD_NO_SA: /* qemu-nbd without socket activation */
|
||||
*ipaddr = "localhost";
|
||||
*port = get_local_port ();
|
||||
if (*port == -1) return -1;
|
||||
return start_qemu_nbd (device, *ipaddr, *port, NULL, 0);
|
||||
|
||||
case NBDKIT: /* nbdkit with socket activation */
|
||||
*ipaddr = "localhost";
|
||||
*port = open_listening_socket (*ipaddr, &fds, &nr_fds);
|
||||
if (*port == -1) return -1;
|
||||
pid = start_nbdkit (device, *ipaddr, *port, fds, nr_fds);
|
||||
for (i = 0; i < nr_fds; ++i)
|
||||
close (fds[i]);
|
||||
free (fds);
|
||||
return pid;
|
||||
|
||||
case NBDKIT_NO_SA: /* nbdkit without socket activation */
|
||||
*ipaddr = "localhost";
|
||||
*port = get_local_port ();
|
||||
if (*port == -1) return -1;
|
||||
return start_nbdkit (device, *ipaddr, *port, NULL, 0);
|
||||
}
|
||||
|
||||
abort ();
|
||||
}
|
||||
|
||||
#define FIRST_SOCKET_ACTIVATION_FD 3
|
||||
|
||||
/**
|
||||
* Set up file descriptors and environment variables for
|
||||
* socket activation.
|
||||
*
|
||||
* Note this function runs in the child between fork and exec.
|
||||
*/
|
||||
static inline void
|
||||
socket_activation (int *fds, size_t nr_fds)
|
||||
{
|
||||
size_t i;
|
||||
char nr_fds_str[16];
|
||||
char pid_str[16];
|
||||
|
||||
if (fds == NULL) return;
|
||||
|
||||
for (i = 0; i < nr_fds; ++i) {
|
||||
int fd = FIRST_SOCKET_ACTIVATION_FD + i;
|
||||
if (fds[i] != fd) {
|
||||
dup2 (fds[i], fd);
|
||||
close (fds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
snprintf (nr_fds_str, sizeof nr_fds_str, "%zu", nr_fds);
|
||||
setenv ("LISTEN_FDS", nr_fds_str, 1);
|
||||
snprintf (pid_str, sizeof pid_str, "%d", (int) getpid ());
|
||||
setenv ("LISTEN_PID", pid_str, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a local L<qemu-nbd(1)> process.
|
||||
*
|
||||
* If we are using socket activation, C<fds> and C<nr_fds> will
|
||||
* contain the locally pre-opened file descriptors for this.
|
||||
* Otherwise if C<fds == NULL> we pass the port number.
|
||||
*
|
||||
* Returns the process ID (E<gt> 0) or C<0> if there is an error.
|
||||
*/
|
||||
static pid_t
|
||||
start_qemu_nbd (const char *device,
|
||||
const char *ipaddr, int port, int *fds, size_t nr_fds)
|
||||
{
|
||||
pid_t pid;
|
||||
char port_str[64];
|
||||
|
||||
#if DEBUG_STDERR
|
||||
fprintf (stderr, "starting qemu-nbd for %s on %s:%d%s\n",
|
||||
device, ipaddr, port,
|
||||
fds == NULL ? "" : " using socket activation");
|
||||
#endif
|
||||
|
||||
snprintf (port_str, sizeof port_str, "%d", port);
|
||||
|
||||
pid = fork ();
|
||||
if (pid == -1) {
|
||||
set_nbd_error ("fork: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pid == 0) { /* Child. */
|
||||
close (0);
|
||||
if (open ("/dev/null", O_RDONLY) == -1) {
|
||||
perror ("open: /dev/null");
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (fds == NULL) { /* without socket activation */
|
||||
execlp ("qemu-nbd",
|
||||
"qemu-nbd",
|
||||
"-r", /* readonly (vital!) */
|
||||
"-p", port_str, /* listening port */
|
||||
"-t", /* persistent */
|
||||
"-f", "raw", /* force raw format */
|
||||
"-b", ipaddr, /* listen only on loopback interface */
|
||||
"--cache=unsafe", /* use unsafe caching for speed */
|
||||
device, /* a device like /dev/sda */
|
||||
NULL);
|
||||
perror ("qemu-nbd");
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
else { /* socket activation */
|
||||
socket_activation (fds, nr_fds);
|
||||
|
||||
execlp ("qemu-nbd",
|
||||
"qemu-nbd",
|
||||
"-r", /* readonly (vital!) */
|
||||
"-t", /* persistent */
|
||||
"-f", "raw", /* force raw format */
|
||||
"--cache=unsafe", /* use unsafe caching for speed */
|
||||
device, /* a device like /dev/sda */
|
||||
NULL);
|
||||
perror ("qemu-nbd");
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Parent. */
|
||||
return pid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a local L<nbdkit(1)> process using the
|
||||
* L<nbdkit-file-plugin(1)>.
|
||||
*
|
||||
* If we are using socket activation, C<fds> and C<nr_fds> will
|
||||
* contain the locally pre-opened file descriptors for this.
|
||||
* Otherwise if C<fds == NULL> we pass the port number.
|
||||
*
|
||||
* Returns the process ID (E<gt> 0) or C<0> if there is an error.
|
||||
*/
|
||||
static pid_t
|
||||
start_nbdkit (const char *device,
|
||||
const char *ipaddr, int port, int *fds, size_t nr_fds)
|
||||
{
|
||||
pid_t pid;
|
||||
char port_str[64];
|
||||
CLEANUP_FREE char *file_str = NULL;
|
||||
|
||||
#if DEBUG_STDERR
|
||||
fprintf (stderr, "starting nbdkit for %s on %s:%d%s\n",
|
||||
device, ipaddr, port,
|
||||
fds == NULL ? "" : " using socket activation");
|
||||
#endif
|
||||
|
||||
snprintf (port_str, sizeof port_str, "%d", port);
|
||||
|
||||
if (asprintf (&file_str, "file=%s", device) == -1)
|
||||
error (EXIT_FAILURE, errno, "asprintf");
|
||||
|
||||
pid = fork ();
|
||||
if (pid == -1) {
|
||||
set_nbd_error ("fork: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pid == 0) { /* Child. */
|
||||
close (0);
|
||||
if (open ("/dev/null", O_RDONLY) == -1) {
|
||||
perror ("open: /dev/null");
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (fds == NULL) { /* without socket activation */
|
||||
execlp ("nbdkit",
|
||||
"nbdkit",
|
||||
"-r", /* readonly (vital!) */
|
||||
"-p", port_str, /* listening port */
|
||||
"-i", ipaddr, /* listen only on loopback interface */
|
||||
"-f", /* don't fork */
|
||||
"file", /* file plugin */
|
||||
file_str, /* a device like file=/dev/sda */
|
||||
NULL);
|
||||
perror ("nbdkit");
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
else { /* socket activation */
|
||||
socket_activation (fds, nr_fds);
|
||||
|
||||
execlp ("nbdkit",
|
||||
"nbdkit",
|
||||
"-r", /* readonly (vital!) */
|
||||
"-f", /* don't fork */
|
||||
"file", /* file plugin */
|
||||
file_str, /* a device like file=/dev/sda */
|
||||
NULL);
|
||||
perror ("nbdkit");
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Parent. */
|
||||
return pid;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used when we are starting an NBD server that does not
|
||||
* support socket activation. We have to pass the '-p' option to
|
||||
* the NBD server, but there's no good way to choose a free port,
|
||||
* so we have to just guess.
|
||||
*
|
||||
* Returns the port number on success or C<-1> on error.
|
||||
*/
|
||||
static int
|
||||
get_local_port (void)
|
||||
{
|
||||
int port = nbd_local_port;
|
||||
nbd_local_port++;
|
||||
return port;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used when we are starting an NBD server which supports
|
||||
* socket activation. We can open a listening socket on an unused
|
||||
* local port and return it.
|
||||
*
|
||||
* Returns the port number on success or C<-1> on error.
|
||||
*
|
||||
* The file descriptor(s) bound are returned in the array *fds, *nr_fds.
|
||||
* The caller must free the array.
|
||||
*/
|
||||
static int
|
||||
open_listening_socket (const char *ipaddr, int **fds, size_t *nr_fds)
|
||||
{
|
||||
int port;
|
||||
char port_str[16];
|
||||
|
||||
/* This just ensures we don't try the port we previously bound to. */
|
||||
port = nbd_local_port;
|
||||
|
||||
/* Search for a free port. */
|
||||
for (; port < 60000; ++port) {
|
||||
snprintf (port_str, sizeof port_str, "%d", port);
|
||||
if (bind_tcpip_socket (ipaddr, port_str, fds, nr_fds) == 0) {
|
||||
/* See above. */
|
||||
nbd_local_port = port + 1;
|
||||
return port;
|
||||
}
|
||||
}
|
||||
|
||||
set_nbd_error ("cannot find a free local port");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
bind_tcpip_socket (const char *ipaddr, const char *port,
|
||||
int **fds_rtn, size_t *nr_fds_rtn)
|
||||
{
|
||||
struct addrinfo *ai = NULL;
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *a;
|
||||
int err;
|
||||
int *fds = NULL;
|
||||
size_t nr_fds;
|
||||
int addr_in_use = 0;
|
||||
|
||||
memset (&hints, 0, sizeof hints);
|
||||
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
err = getaddrinfo (ipaddr, port, &hints, &ai);
|
||||
if (err != 0) {
|
||||
#if DEBUG_STDERR
|
||||
fprintf (stderr, "%s: getaddrinfo: %s: %s: %s",
|
||||
getprogname (), ipaddr ? ipaddr : "<any>", port,
|
||||
gai_strerror (err));
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
nr_fds = 0;
|
||||
|
||||
for (a = ai; a != NULL; a = a->ai_next) {
|
||||
int sock, opt;
|
||||
|
||||
sock = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
|
||||
if (sock == -1)
|
||||
error (EXIT_FAILURE, errno, "socket");
|
||||
|
||||
opt = 1;
|
||||
if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt) == -1)
|
||||
perror ("setsockopt: SO_REUSEADDR");
|
||||
|
||||
#ifdef IPV6_V6ONLY
|
||||
if (a->ai_family == PF_INET6) {
|
||||
if (setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof opt) == -1)
|
||||
perror ("setsockopt: IPv6 only");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bind (sock, a->ai_addr, a->ai_addrlen) == -1) {
|
||||
if (errno == EADDRINUSE) {
|
||||
addr_in_use = 1;
|
||||
close (sock);
|
||||
continue;
|
||||
}
|
||||
perror ("bind");
|
||||
close (sock);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (listen (sock, SOMAXCONN) == -1) {
|
||||
perror ("listen");
|
||||
close (sock);
|
||||
continue;
|
||||
}
|
||||
|
||||
nr_fds++;
|
||||
fds = realloc (fds, sizeof (int) * nr_fds);
|
||||
if (!fds)
|
||||
error (EXIT_FAILURE, errno, "realloc");
|
||||
fds[nr_fds-1] = sock;
|
||||
}
|
||||
|
||||
freeaddrinfo (ai);
|
||||
|
||||
if (nr_fds == 0 && addr_in_use) {
|
||||
#if DEBUG_STDERR
|
||||
fprintf (stderr, "%s: unable to bind to %s:%s: %s\n",
|
||||
getprogname (), ipaddr ? ipaddr : "<any>", port,
|
||||
strerror (EADDRINUSE));
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if DEBUG_STDERR
|
||||
fprintf (stderr, "%s: bound to IP address %s:%s (%zu socket(s))\n",
|
||||
getprogname (), ipaddr ? ipaddr : "<any>", port, nr_fds);
|
||||
#endif
|
||||
|
||||
*fds_rtn = fds;
|
||||
*nr_fds_rtn = nr_fds;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for a local NBD server to start and be listening for
|
||||
* connections.
|
||||
*/
|
||||
int
|
||||
wait_for_nbd_server_to_start (const char *ipaddr, int port)
|
||||
{
|
||||
int sockfd = -1;
|
||||
int result = -1;
|
||||
time_t start_t, now_t;
|
||||
struct timespec half_sec = { .tv_sec = 0, .tv_nsec = 500000000 };
|
||||
struct timeval timeout = { .tv_usec = 0 };
|
||||
char magic[8]; /* NBDMAGIC */
|
||||
size_t bytes_read = 0;
|
||||
ssize_t recvd;
|
||||
|
||||
time (&start_t);
|
||||
|
||||
for (;;) {
|
||||
time (&now_t);
|
||||
|
||||
if (now_t - start_t >= WAIT_NBD_TIMEOUT) {
|
||||
set_nbd_error ("timed out waiting for NBD server to start");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Source port for probing NBD server should be one greater than
|
||||
* port. It's not guaranteed to always bind to this port, but it
|
||||
* will hint the kernel to start there and try incrementally
|
||||
* higher ports if needed. This avoids the case where the kernel
|
||||
* selects port as our source port, and we immediately connect to
|
||||
* ourself. See:
|
||||
* https://bugzilla.redhat.com/show_bug.cgi?id=1167774#c9
|
||||
*/
|
||||
sockfd = connect_with_source_port (ipaddr, port, port+1);
|
||||
if (sockfd >= 0)
|
||||
break;
|
||||
|
||||
nanosleep (&half_sec, NULL);
|
||||
}
|
||||
|
||||
time (&now_t);
|
||||
timeout.tv_sec = (start_t + WAIT_NBD_TIMEOUT) - now_t;
|
||||
if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout) == -1) {
|
||||
set_nbd_error ("waiting for NBD server to start: "
|
||||
"setsockopt(SO_RCVTIMEO): %m");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
do {
|
||||
recvd = recv (sockfd, magic, sizeof magic - bytes_read, 0);
|
||||
|
||||
if (recvd == -1) {
|
||||
set_nbd_error ("waiting for NBD server to start: recv: %m");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
bytes_read += recvd;
|
||||
} while (bytes_read < sizeof magic);
|
||||
|
||||
if (memcmp (magic, "NBDMAGIC", sizeof magic) != 0) {
|
||||
set_nbd_error ("waiting for NBD server to start: "
|
||||
"'NBDMAGIC' was not received from NBD server");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
cleanup:
|
||||
if (sockfd >= 0)
|
||||
close (sockfd);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to C<hostname:dest_port>, resolving the address using
|
||||
* L<getaddrinfo(3)>.
|
||||
*
|
||||
* This also sets the source port of the connection to the first free
|
||||
* port number E<ge> C<source_port>.
|
||||
*
|
||||
* This may involve multiple connections - to IPv4 and IPv6 for
|
||||
* instance.
|
||||
*/
|
||||
static int
|
||||
connect_with_source_port (const char *hostname, int dest_port, int source_port)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *results, *rp;
|
||||
char dest_port_str[16];
|
||||
int r, sockfd = -1;
|
||||
int reuseaddr = 1;
|
||||
|
||||
snprintf (dest_port_str, sizeof dest_port_str, "%d", dest_port);
|
||||
|
||||
memset (&hints, 0, sizeof hints);
|
||||
hints.ai_family = AF_UNSPEC; /* allow IPv4 or IPv6 */
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_NUMERICSERV; /* numeric dest port number */
|
||||
hints.ai_protocol = 0; /* any protocol */
|
||||
|
||||
r = getaddrinfo (hostname, dest_port_str, &hints, &results);
|
||||
if (r != 0) {
|
||||
set_nbd_error ("getaddrinfo: %s/%s: %s",
|
||||
hostname, dest_port_str, gai_strerror (r));
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (rp = results; rp != NULL; rp = rp->ai_next) {
|
||||
sockfd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||
if (sockfd == -1)
|
||||
continue;
|
||||
|
||||
/* If we run p2v repeatedly (say, running the tests in a loop),
|
||||
* there's a decent chance we'll end up trying to bind() to a port
|
||||
* that is in TIME_WAIT from a prior run. Handle that gracefully
|
||||
* with SO_REUSEADDR.
|
||||
*/
|
||||
if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR,
|
||||
&reuseaddr, sizeof reuseaddr) == -1)
|
||||
perror ("warning: setsockopt");
|
||||
|
||||
/* Need to bind the source port. */
|
||||
if (bind_source_port (sockfd, rp->ai_family, source_port) == -1) {
|
||||
close (sockfd);
|
||||
sockfd = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Connect. */
|
||||
if (connect (sockfd, rp->ai_addr, rp->ai_addrlen) == -1) {
|
||||
set_nbd_error ("waiting for NBD server to start: "
|
||||
"connect to %s/%s: %m",
|
||||
hostname, dest_port_str);
|
||||
close (sockfd);
|
||||
sockfd = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
freeaddrinfo (results);
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
static int
|
||||
bind_source_port (int sockfd, int family, int source_port)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *results, *rp;
|
||||
char source_port_str[16];
|
||||
int r;
|
||||
|
||||
snprintf (source_port_str, sizeof source_port_str, "%d", source_port);
|
||||
|
||||
memset (&hints, 0, sizeof (hints));
|
||||
hints.ai_family = family;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* numeric port number */
|
||||
hints.ai_protocol = 0; /* any protocol */
|
||||
|
||||
r = getaddrinfo ("localhost", source_port_str, &hints, &results);
|
||||
if (r != 0) {
|
||||
set_nbd_error ("getaddrinfo (bind): localhost/%s: %s",
|
||||
source_port_str, gai_strerror (r));
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (rp = results; rp != NULL; rp = rp->ai_next) {
|
||||
if (bind (sockfd, rp->ai_addr, rp->ai_addrlen) == 0)
|
||||
goto bound;
|
||||
}
|
||||
|
||||
set_nbd_error ("waiting for NBD server to start: "
|
||||
"bind to source port %d: %m",
|
||||
source_port);
|
||||
freeaddrinfo (results);
|
||||
return -1;
|
||||
|
||||
bound:
|
||||
freeaddrinfo (results);
|
||||
return 0;
|
||||
}
|
||||
136
p2v/p2v.h
136
p2v/p2v.h
@@ -1,136 +0,0 @@
|
||||
/* virt-p2v
|
||||
* Copyright (C) 2009-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.
|
||||
*/
|
||||
|
||||
#ifndef P2V_H
|
||||
#define P2V_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Send various debug information to stderr. Harmless and useful, so
|
||||
* can be left enabled in production builds.
|
||||
*/
|
||||
#define DEBUG_STDERR 1
|
||||
|
||||
#include "miniexpect.h"
|
||||
#include "p2v-config.h"
|
||||
|
||||
#include "guestfs-utils.h"
|
||||
|
||||
/* All disks / removable media / network interfaces discovered
|
||||
* when the program started. Do not change these.
|
||||
*/
|
||||
extern char **all_disks;
|
||||
extern char **all_removable;
|
||||
extern char **all_interfaces;
|
||||
|
||||
/* True if running inside the virt-p2v ISO environment. Various
|
||||
* dangerous functions such as the "Reboot" button are disabled if
|
||||
* this is false.
|
||||
*/
|
||||
extern int is_iso_environment;
|
||||
|
||||
/* True if virt-v2v supports the --colours option. */
|
||||
extern int feature_colours_option;
|
||||
|
||||
/* virt-p2v --colours option (used by ansi_* macros). */
|
||||
extern int force_colour;
|
||||
|
||||
/* cpuid.c */
|
||||
extern void get_cpu_config (struct cpu_config *);
|
||||
|
||||
/* rtc.c */
|
||||
extern void get_rtc_config (struct rtc_config *);
|
||||
|
||||
/* kernel-cmdline.c */
|
||||
extern char **parse_cmdline_string (const char *cmdline);
|
||||
extern char **parse_proc_cmdline (void);
|
||||
extern const char *get_cmdline_key (char **cmdline, const char *key);
|
||||
|
||||
#define CMDLINE_SOURCE_COMMAND_LINE 1 /* --cmdline */
|
||||
#define CMDLINE_SOURCE_PROC_CMDLINE 2 /* /proc/cmdline */
|
||||
|
||||
/* kernel-config.c */
|
||||
extern void update_config_from_kernel_cmdline (struct config *config, char **cmdline);
|
||||
|
||||
/* kernel.c */
|
||||
extern void kernel_conversion (struct config *, char **cmdline, int cmdline_source);
|
||||
|
||||
/* gui.c */
|
||||
extern void gui_conversion (struct config *);
|
||||
|
||||
/* conversion.c */
|
||||
struct data_conn { /* Data per NBD connection / physical disk. */
|
||||
mexp_h *h; /* miniexpect handle to ssh */
|
||||
pid_t nbd_pid; /* NBD server PID */
|
||||
int nbd_remote_port; /* remote NBD port on conversion server */
|
||||
};
|
||||
|
||||
extern int start_conversion (struct config *, void (*notify_ui) (int type, const char *data));
|
||||
#define NOTIFY_LOG_DIR 1 /* location of remote log directory */
|
||||
#define NOTIFY_REMOTE_MESSAGE 2 /* log message from remote virt-v2v */
|
||||
#define NOTIFY_STATUS 3 /* stage in conversion process */
|
||||
extern const char *get_conversion_error (void);
|
||||
extern void cancel_conversion (void);
|
||||
extern int conversion_is_running (void);
|
||||
|
||||
/* physical-xml.c */
|
||||
extern void generate_physical_xml (struct config *, struct data_conn *, const char *filename);
|
||||
|
||||
/* inhibit.c */
|
||||
extern int inhibit_power_saving (void);
|
||||
|
||||
/* ssh.c */
|
||||
extern int test_connection (struct config *);
|
||||
extern mexp_h *open_data_connection (struct config *, const char *local_ipaddr, int local_port, int *remote_port);
|
||||
extern mexp_h *start_remote_connection (struct config *, const char *remote_dir);
|
||||
extern const char *get_ssh_error (void);
|
||||
extern int scp_file (struct config *config, const char *target, const char *local, ...) __attribute__((sentinel));
|
||||
|
||||
/* nbd.c */
|
||||
extern void set_nbd_option (const char *opt);
|
||||
extern void test_nbd_servers (void);
|
||||
extern pid_t start_nbd_server (const char **ipaddr, int *port, const char *device);
|
||||
extern int wait_for_nbd_server_to_start (const char *ipaddr, int port);
|
||||
const char *get_nbd_error (void);
|
||||
|
||||
/* utils.c */
|
||||
extern uint64_t get_blockdev_size (const char *dev);
|
||||
extern char *get_blockdev_model (const char *dev);
|
||||
extern char *get_blockdev_serial (const char *dev);
|
||||
extern char *get_if_addr (const char *if_name);
|
||||
extern char *get_if_vendor (const char *if_name, int truncate);
|
||||
extern void wait_network_online (const struct config *);
|
||||
|
||||
/* whole-file.c */
|
||||
extern int read_whole_file (const char *filename, char **data_r, size_t *size_r);
|
||||
|
||||
/* virt-v2v version and features (read from remote). */
|
||||
extern char *v2v_version;
|
||||
|
||||
/* input and output drivers (read from remote). */
|
||||
extern char **input_drivers;
|
||||
extern char **output_drivers;
|
||||
|
||||
/* about-authors.c */
|
||||
extern const char *authors[];
|
||||
extern const char *qa[];
|
||||
extern const char *documenters[];
|
||||
extern const char *others[];
|
||||
|
||||
#endif /* P2V_H */
|
||||
193
p2v/p2v.ks.in
193
p2v/p2v.ks.in
@@ -1,193 +0,0 @@
|
||||
# Kickstart file for creating the virt-p2v ISO.
|
||||
# (C) Copyright 2014-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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
# Generated by virt-p2v-make-kickstart __PACKAGE_VERSION_FULL__
|
||||
|
||||
lang en_US.UTF-8
|
||||
keyboard us
|
||||
timezone --utc GMT
|
||||
|
||||
rootpw --plaintext p2v
|
||||
|
||||
selinux --enforcing
|
||||
firewall --enabled
|
||||
|
||||
# Make sure that systemd doesn't rename the network device. We have
|
||||
# to tell Anaconda we're using eth0, *and* we have to pass
|
||||
# net.ifnames=0 on the kernel command line.
|
||||
network --bootproto=dhcp --device=eth0
|
||||
bootloader --location=mbr --append="console=tty0 console=ttyS0,115200 rd_NO_PLYMOUTH net.ifnames=0"
|
||||
|
||||
zerombr
|
||||
clearpart --all --initlabel
|
||||
part / --size 3000 --fstype ext4
|
||||
|
||||
reboot
|
||||
|
||||
# Repository lines:
|
||||
__REPOS__
|
||||
|
||||
# Packages to install in the ISO. For dependencies, see
|
||||
# p2v/Makefile.am. Note that libguestfs is NOT required by virt-p2v.
|
||||
|
||||
%packages
|
||||
|
||||
@core
|
||||
|
||||
# rpm must be installed, else you'll hit RHBZ#1089566.
|
||||
rpm
|
||||
|
||||
# Note you must have a kernel, else the boot menu won't work:
|
||||
kernel
|
||||
|
||||
# This is required in order for RHEL to set the root password.
|
||||
passwd
|
||||
|
||||
# RHEL needs this in order to get networking.
|
||||
NetworkManager
|
||||
|
||||
# Required to run firewall --enabled kickstart command:
|
||||
firewalld
|
||||
|
||||
# Needed by post script to unpack the blobs.
|
||||
/usr/bin/base64
|
||||
/usr/bin/gzip
|
||||
|
||||
# Work around https://bugzilla.redhat.com/show_bug.cgi?id=1182362
|
||||
tar
|
||||
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=1168223
|
||||
dracut-live
|
||||
|
||||
# The dependencies of virt-p2v.
|
||||
__DEPENDENCIES__
|
||||
|
||||
# Extra packages requested by the user via the virt-p2v-make-kickstart
|
||||
# --install option (if any).
|
||||
__EXTRA_PACKAGES__
|
||||
|
||||
%end
|
||||
|
||||
# Post-install configuration.
|
||||
|
||||
%post
|
||||
|
||||
# Base64-decoding of SSH Identity.
|
||||
|
||||
base64 -d -i > /var/tmp/id_rsa << EOF
|
||||
__BASE64_SSH_IDENTITY__
|
||||
EOF
|
||||
if test -s /var/tmp/id_rsa; then
|
||||
chmod 0600 /var/tmp/id_rsa
|
||||
else
|
||||
rm /var/tmp/id_rsa
|
||||
fi
|
||||
|
||||
# Base64-decoding of /etc/issue
|
||||
|
||||
base64 -d -i > /etc/issue << EOF
|
||||
__BASE64_ISSUE__
|
||||
EOF
|
||||
|
||||
cp /etc/issue /etc/issue.net
|
||||
|
||||
# Base64-decoding of launch-virt-p2v
|
||||
|
||||
base64 -d -i > /usr/bin/launch-virt-p2v <<EOF
|
||||
__BASE64_LAUNCH_VIRT_P2V__
|
||||
EOF
|
||||
|
||||
chmod 0755 /usr/bin/launch-virt-p2v
|
||||
|
||||
# Base64-decoding of p2v.service unit file
|
||||
|
||||
base64 -d -i > /etc/systemd/system/p2v.service <<EOF
|
||||
__BASE64_P2V_SERVICE__
|
||||
EOF
|
||||
|
||||
# Base64-decoding of virt-p2v binary
|
||||
# md5(virt-p2v) = __MD5SUM_VIRT_P2V__
|
||||
|
||||
base64 -d -i <<EOF | gzip -cd > /usr/bin/virt-p2v
|
||||
__BASE64_VIRT_P2V__
|
||||
EOF
|
||||
|
||||
chmod 0755 /usr/bin/virt-p2v
|
||||
|
||||
# Update the default getty target to login automatically as root without
|
||||
# prompting for a password
|
||||
sed -i 's/^ExecStart=\(.*\)/ExecStart=\1 -a root/' \
|
||||
/usr/lib/systemd/system/getty@.service
|
||||
|
||||
# Reserve tty1 as a getty so we can document it clearly
|
||||
echo ReserveVT=1 >> /etc/systemd/logind.conf
|
||||
|
||||
# Force text mode
|
||||
systemctl set-default multi-user.target
|
||||
|
||||
# Start p2v service
|
||||
systemctl enable p2v.service
|
||||
|
||||
# Disable ssh service (RHBZ#1248678)
|
||||
systemctl disable sshd.service
|
||||
|
||||
%end
|
||||
|
||||
%post --nochroot
|
||||
|
||||
PRODUCT='Virt P2V'
|
||||
PRODUCT_SHORT='virt-p2v'
|
||||
PACKAGE='__PACKAGE_NAME__'
|
||||
VERSION='__PACKAGE_VERSION__'
|
||||
|
||||
echo "Customizing boot menu"
|
||||
sed -i -e '
|
||||
# Put product information at the top of the file
|
||||
1 {
|
||||
i '"say $PRODUCT $VERSION"'
|
||||
i '"menu title $PRODUCT_SHORT $VERSION"'
|
||||
}
|
||||
|
||||
# Remove any existing menu title
|
||||
/^menu title .*/d
|
||||
|
||||
# Set the default timeout to 60 seconds
|
||||
s/^timeout .*/timeout 600/
|
||||
' $LIVE_ROOT/isolinux/isolinux.cfg
|
||||
|
||||
# store image version info in the ISO
|
||||
cat > $LIVE_ROOT/isolinux/version <<EOF
|
||||
PRODUCT='$PRODUCT'
|
||||
PRODUCT_SHORT='${PRODUCT_SHORT}'
|
||||
#PRODUCT_CODE=$PRODUCT_CODE
|
||||
#RECIPE_SHA256=$RECIPE_SHA256
|
||||
#RECIPE_RPM=$RECIPE_RPM
|
||||
PACKAGE=$PACKAGE
|
||||
VERSION=$VERSION
|
||||
EOF
|
||||
|
||||
# overwrite user visible banners with the image versioning info
|
||||
cat > $INSTALL_ROOT/etc/$PACKAGE-release <<EOF
|
||||
$PRODUCT release $VERSION
|
||||
EOF
|
||||
|
||||
# replace initramfs if regenerated
|
||||
if [ -f "$INSTALL_ROOT/initrd0.img" ]; then
|
||||
mv -v "$INSTALL_ROOT/initrd0.img" "$LIVE_ROOT/isolinux/initrd0.img"
|
||||
fi
|
||||
|
||||
%end
|
||||
@@ -1,38 +0,0 @@
|
||||
# libguestfs virt-p2v ISO
|
||||
# Copyright (C) 2009-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.
|
||||
|
||||
# NB: This cannot be called "virt-p2v.service" because on Fedora the
|
||||
# virt- prefix will cause it to get the wrong SELinux label.
|
||||
|
||||
[Unit]
|
||||
Description=p2v service
|
||||
# For the GUI, we cannot necessarily wait for the network to come
|
||||
# online, since that may require the "Configure Network" dialog. For
|
||||
# the command line, we would like the network to be online, but we
|
||||
# test that within virt-p2v itself. Therefore use network.target
|
||||
# here, not network-online.target.
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/launch-virt-p2v
|
||||
RemainAfterExit=yes
|
||||
StandardOutput=journal+console
|
||||
StandardError=inherit
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -1,304 +0,0 @@
|
||||
/* virt-p2v
|
||||
* Copyright (C) 2009-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 the F<physical.xml> file, which is a piece of phony libvirt
|
||||
* XML used to communicate the metadata of the physical machine to
|
||||
* virt-v2v.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
|
||||
#include <libxml/xmlwriter.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "getprogname.h"
|
||||
|
||||
#include "libxml2-writer-macros.h"
|
||||
|
||||
#include "p2v.h"
|
||||
|
||||
/* This macro is used by the macros in "libxml2-writer-macros.h"
|
||||
* when an error occurs.
|
||||
*/
|
||||
#define xml_error(fn) \
|
||||
error (EXIT_FAILURE, errno, \
|
||||
"%s:%d: error constructing XML near call to \"%s\"", \
|
||||
__FILE__, __LINE__, (fn));
|
||||
|
||||
static const char *map_interface_to_network (struct config *, const char *interface);
|
||||
|
||||
/**
|
||||
* Write the libvirt XML for this physical machine.
|
||||
*
|
||||
* Note this is not actually input for libvirt. It's input for
|
||||
* virt-v2v on the conversion server. Virt-v2v will (if necessary)
|
||||
* generate the final libvirt XML.
|
||||
*/
|
||||
void
|
||||
generate_physical_xml (struct config *config, struct data_conn *data_conns,
|
||||
const char *filename)
|
||||
{
|
||||
uint64_t memkb;
|
||||
CLEANUP_XMLFREETEXTWRITER xmlTextWriterPtr xo = NULL;
|
||||
size_t i;
|
||||
|
||||
xo = xmlNewTextWriterFilename (filename, 0);
|
||||
if (xo == NULL)
|
||||
error (EXIT_FAILURE, errno, "xmlNewTextWriterFilename");
|
||||
|
||||
if (xmlTextWriterSetIndent (xo, 1) == -1 ||
|
||||
xmlTextWriterSetIndentString (xo, BAD_CAST " ") == -1)
|
||||
error (EXIT_FAILURE, errno, "could not set XML indent");
|
||||
if (xmlTextWriterStartDocument (xo, NULL, NULL, NULL) == -1)
|
||||
error (EXIT_FAILURE, errno, "xmlTextWriterStartDocument");
|
||||
|
||||
memkb = config->memory / 1024;
|
||||
|
||||
comment (" %s %s ", getprogname (), PACKAGE_VERSION_FULL);
|
||||
|
||||
comment
|
||||
(" NOTE!\n"
|
||||
"\n"
|
||||
" This libvirt XML is generated by the virt-p2v front end, in\n"
|
||||
" order to communicate with the backend virt-v2v process running\n"
|
||||
" on the conversion server. It is a minimal description of the\n"
|
||||
" physical machine. If the target of the conversion is libvirt,\n"
|
||||
" then virt-v2v will generate the real target libvirt XML, which\n"
|
||||
" has only a little to do with the XML in this file.\n"
|
||||
"\n"
|
||||
" TL;DR: Don't try to load this XML into libvirt. ");
|
||||
|
||||
start_element ("domain") {
|
||||
attribute ("type", "physical");
|
||||
|
||||
single_element ("name", config->guestname);
|
||||
|
||||
start_element ("memory") {
|
||||
attribute ("unit", "KiB");
|
||||
string_format ("%" PRIu64, memkb);
|
||||
} end_element ();
|
||||
|
||||
start_element ("currentMemory") {
|
||||
attribute ("unit", "KiB");
|
||||
string_format ("%" PRIu64, memkb);
|
||||
} end_element ();
|
||||
|
||||
single_element_format ("vcpu", "%d", config->vcpus);
|
||||
|
||||
if (config->cpu.vendor || config->cpu.model ||
|
||||
config->cpu.sockets || config->cpu.cores || config->cpu.threads) {
|
||||
/* https://libvirt.org/formatdomain.html#elementsCPU */
|
||||
start_element ("cpu") {
|
||||
attribute ("match", "minimum");
|
||||
if (config->cpu.vendor)
|
||||
single_element ("vendor", config->cpu.vendor);
|
||||
if (config->cpu.model) {
|
||||
start_element ("model") {
|
||||
attribute ("fallback", "allow");
|
||||
string (config->cpu.model);
|
||||
} end_element ();
|
||||
}
|
||||
if (config->cpu.sockets || config->cpu.cores || config->cpu.threads) {
|
||||
start_element ("topology") {
|
||||
if (config->cpu.sockets)
|
||||
attribute_format ("sockets", "%u", config->cpu.sockets);
|
||||
if (config->cpu.cores)
|
||||
attribute_format ("cores", "%u", config->cpu.cores);
|
||||
if (config->cpu.threads)
|
||||
attribute_format ("threads", "%u", config->cpu.threads);
|
||||
} end_element ();
|
||||
}
|
||||
} end_element ();
|
||||
}
|
||||
|
||||
switch (config->rtc.basis) {
|
||||
case BASIS_UNKNOWN:
|
||||
/* Don't emit any <clock> element. */
|
||||
break;
|
||||
case BASIS_UTC:
|
||||
start_element ("clock") {
|
||||
if (config->rtc.offset == 0)
|
||||
attribute ("offset", "utc");
|
||||
else {
|
||||
attribute ("offset", "variable");
|
||||
attribute ("basis", "utc");
|
||||
attribute_format ("adjustment", "%d", config->rtc.offset);
|
||||
}
|
||||
} end_element ();
|
||||
break;
|
||||
case BASIS_LOCALTIME:
|
||||
start_element ("clock") {
|
||||
attribute ("offset", "localtime");
|
||||
/* config->rtc.offset is always 0 in this case */
|
||||
} end_element ();
|
||||
break;
|
||||
}
|
||||
|
||||
start_element ("os") {
|
||||
start_element ("type") {
|
||||
attribute ("arch", host_cpu);
|
||||
string ("hvm");
|
||||
} end_element ();
|
||||
} end_element ();
|
||||
|
||||
start_element ("features") {
|
||||
if (config->cpu.acpi) empty_element ("acpi");
|
||||
if (config->cpu.apic) empty_element ("apic");
|
||||
if (config->cpu.pae) empty_element ("pae");
|
||||
} end_element ();
|
||||
|
||||
start_element ("devices") {
|
||||
|
||||
for (i = 0; config->disks[i] != NULL; ++i) {
|
||||
char target_dev[64];
|
||||
|
||||
if (config->disks[i][0] == '/') {
|
||||
target_sd:
|
||||
memcpy (target_dev, "sd", 2);
|
||||
guestfs_int_drive_name (i, &target_dev[2]);
|
||||
} else {
|
||||
if (strlen (config->disks[i]) <= sizeof (target_dev) - 1)
|
||||
strcpy (target_dev, config->disks[i]);
|
||||
else
|
||||
goto target_sd;
|
||||
}
|
||||
|
||||
start_element ("disk") {
|
||||
attribute ("type", "network");
|
||||
attribute ("device", "disk");
|
||||
start_element ("driver") {
|
||||
attribute ("name", "qemu");
|
||||
attribute ("type", "raw");
|
||||
} end_element ();
|
||||
start_element ("source") {
|
||||
attribute ("protocol", "nbd");
|
||||
start_element ("host") {
|
||||
attribute ("name", "localhost");
|
||||
attribute_format ("port", "%d", data_conns[i].nbd_remote_port);
|
||||
} end_element ();
|
||||
} end_element ();
|
||||
start_element ("target") {
|
||||
attribute ("dev", target_dev);
|
||||
/* XXX Need to set bus to "ide" or "scsi" here. */
|
||||
} end_element ();
|
||||
} end_element ();
|
||||
}
|
||||
|
||||
if (config->removable) {
|
||||
for (i = 0; config->removable[i] != NULL; ++i) {
|
||||
start_element ("disk") {
|
||||
attribute ("type", "network");
|
||||
attribute ("device", "cdrom");
|
||||
start_element ("driver") {
|
||||
attribute ("name", "qemu");
|
||||
attribute ("type", "raw");
|
||||
} end_element ();
|
||||
start_element ("target") {
|
||||
attribute ("dev", config->removable[i]);
|
||||
} end_element ();
|
||||
} end_element ();
|
||||
}
|
||||
}
|
||||
|
||||
if (config->interfaces) {
|
||||
for (i = 0; config->interfaces[i] != NULL; ++i) {
|
||||
const char *target_network;
|
||||
CLEANUP_FREE char *mac_filename = NULL;
|
||||
CLEANUP_FREE char *mac = NULL;
|
||||
|
||||
target_network =
|
||||
map_interface_to_network (config, config->interfaces[i]);
|
||||
|
||||
if (asprintf (&mac_filename, "/sys/class/net/%s/address",
|
||||
config->interfaces[i]) == -1)
|
||||
error (EXIT_FAILURE, errno, "asprintf");
|
||||
if (g_file_get_contents (mac_filename, &mac, NULL, NULL)) {
|
||||
const size_t len = strlen (mac);
|
||||
|
||||
if (len > 0 && mac[len-1] == '\n')
|
||||
mac[len-1] = '\0';
|
||||
}
|
||||
|
||||
start_element ("interface") {
|
||||
attribute ("type", "network");
|
||||
start_element ("source") {
|
||||
attribute ("network", target_network);
|
||||
} end_element ();
|
||||
start_element ("target") {
|
||||
attribute ("dev", config->interfaces[i]);
|
||||
} end_element ();
|
||||
if (mac) {
|
||||
start_element ("mac") {
|
||||
attribute ("address", mac);
|
||||
} end_element ();
|
||||
}
|
||||
} end_element ();
|
||||
}
|
||||
}
|
||||
|
||||
} end_element (); /* </devices> */
|
||||
|
||||
} end_element (); /* </domain> */
|
||||
|
||||
if (xmlTextWriterEndDocument (xo) == -1)
|
||||
error (EXIT_FAILURE, errno, "xmlTextWriterEndDocument");
|
||||
}
|
||||
|
||||
/**
|
||||
* Using C<config-E<gt>network_map>, map the interface to a target
|
||||
* network name. If no map is found, return C<default>. See
|
||||
* L<virt-p2v(1)> documentation of C<"p2v.network"> for how the
|
||||
* network map works.
|
||||
*
|
||||
* Note this returns a static string which is only valid as long as
|
||||
* C<config-E<gt>network_map> is not freed.
|
||||
*/
|
||||
static const char *
|
||||
map_interface_to_network (struct config *config, const char *interface)
|
||||
{
|
||||
size_t i, len;
|
||||
|
||||
if (config->network_map == NULL)
|
||||
return "default";
|
||||
|
||||
for (i = 0; config->network_map[i] != NULL; ++i) {
|
||||
/* The default map maps everything. */
|
||||
if (strchr (config->network_map[i], ':') == NULL)
|
||||
return config->network_map[i];
|
||||
|
||||
/* interface: ? */
|
||||
len = strlen (interface);
|
||||
if (STRPREFIX (config->network_map[i], interface) &&
|
||||
config->network_map[i][len] == ':')
|
||||
return &config->network_map[i][len+1];
|
||||
}
|
||||
|
||||
/* No mapping found. */
|
||||
return "default";
|
||||
}
|
||||
165
p2v/rtc.c
165
p2v/rtc.c
@@ -1,165 +0,0 @@
|
||||
/* virt-p2v
|
||||
* Copyright (C) 2017 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Try to calculate Real Time Clock (RTC) offset from UTC in seconds.
|
||||
* For example if the RTC is 1 hour ahead of UTC, this will return
|
||||
* C<3600>. This is stored in C<config-E<gt>rtc_offset>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <libintl.h>
|
||||
#include <time.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifdef HAVE_LINUX_RTC_H
|
||||
#include <linux/rtc.h>
|
||||
#endif
|
||||
|
||||
#include "getprogname.h"
|
||||
#include "ignore-value.h"
|
||||
|
||||
#include "p2v.h"
|
||||
|
||||
#ifndef HAVE_LINUX_RTC_H
|
||||
void
|
||||
get_rtc_config (struct rtc_config *rtc)
|
||||
{
|
||||
fprintf (stderr, "%s: RTC: compiled without support for /dev/rtc\n",
|
||||
getprogname ());
|
||||
|
||||
rtc->offset = 0;
|
||||
rtc->basis = BASIS_UTC;
|
||||
}
|
||||
|
||||
#else /* HAVE_LINUX_RTC_H */
|
||||
|
||||
/**
|
||||
* Return RTC offset from UTC in seconds, positive numbers meaning
|
||||
* that the RTC is running ahead of UTC.
|
||||
*
|
||||
* In the error case, C<rtcE<gt>offset> is updated with 0 and
|
||||
* C<rtcE<gt>basis> is set to C<BASIS_UNKNOWN>.
|
||||
*/
|
||||
void
|
||||
get_rtc_config (struct rtc_config *rtc)
|
||||
{
|
||||
int fd;
|
||||
struct rtc_time rtm;
|
||||
struct tm tm;
|
||||
time_t rtc_time;
|
||||
time_t system_time;
|
||||
double rf;
|
||||
|
||||
rtc->basis = BASIS_UNKNOWN;
|
||||
rtc->offset = 0;
|
||||
|
||||
fd = open ("/dev/rtc", O_RDONLY);
|
||||
if (fd == -1) {
|
||||
perror ("/dev/rtc");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ioctl (fd, RTC_RD_TIME, &rtm) == -1) {
|
||||
perror ("ioctl: RTC_RD_TIME");
|
||||
close (fd);
|
||||
return;
|
||||
}
|
||||
|
||||
close (fd);
|
||||
|
||||
#ifdef DEBUG_STDERR
|
||||
fprintf (stderr, "%s: RTC: %04d-%02d-%02d %02d:%02d:%02d\n",
|
||||
getprogname (),
|
||||
rtm.tm_year + 1900, rtm.tm_mon + 1, rtm.tm_mday,
|
||||
rtm.tm_hour, rtm.tm_min, rtm.tm_sec);
|
||||
#endif
|
||||
|
||||
/* Convert this to seconds since the epoch. */
|
||||
tm.tm_sec = rtm.tm_sec;
|
||||
tm.tm_min = rtm.tm_min;
|
||||
tm.tm_hour = rtm.tm_hour;
|
||||
tm.tm_mday = rtm.tm_mday;
|
||||
tm.tm_mon = rtm.tm_mon;
|
||||
tm.tm_year = rtm.tm_year;
|
||||
tm.tm_isdst = 0; /* Ignore DST when calculating. */
|
||||
rtc_time = timegm (&tm);
|
||||
if (rtc_time == -1)
|
||||
return; /* Not representable as a Unix time. */
|
||||
|
||||
/* Get system time in UTC. */
|
||||
system_time = time (NULL);
|
||||
|
||||
/* Calculate the difference, rounded to the nearest 15 minutes. */
|
||||
rf = rtc_time - system_time;
|
||||
|
||||
#ifdef DEBUG_STDERR
|
||||
fprintf (stderr, "%s: RTC: %ld system time: %ld difference: %g\n",
|
||||
getprogname (),
|
||||
(long) rtc_time, (long) system_time, rf);
|
||||
#endif
|
||||
|
||||
rf /= 15*60;
|
||||
rf = round (rf);
|
||||
rf *= 15*60;
|
||||
|
||||
/* If it's obviously out of range then print an error and return. */
|
||||
if (rf < -12*60*60 || rf > 14*60*60) {
|
||||
fprintf (stderr,
|
||||
"%s: RTC: offset of RTC from UTC is out of range (%g).\n",
|
||||
getprogname (), rf);
|
||||
return;
|
||||
}
|
||||
|
||||
rtc->offset = (int) rf;
|
||||
|
||||
#ifdef DEBUG_STDERR
|
||||
fprintf (stderr, "%s: RTC: offset of RTC from UTC = %d secs\n",
|
||||
getprogname (), rtc->offset);
|
||||
#endif
|
||||
|
||||
/* Is the hardware clock set to localtime?
|
||||
*
|
||||
* Unfortunately it's not possible to distinguish between UTC and
|
||||
* localtime in timezones that lie along the Greenwich Meridian
|
||||
* (obviously including the UK), when daylight savings time is not
|
||||
* in effect. In that case, prefer UTC.
|
||||
*/
|
||||
localtime_r (&system_time, &tm);
|
||||
if (tm.tm_gmtoff != 0 && tm.tm_gmtoff != rtc->offset)
|
||||
rtc->basis = BASIS_UTC;
|
||||
else {
|
||||
rtc->basis = BASIS_LOCALTIME;
|
||||
rtc->offset = 0;
|
||||
#ifdef DEBUG_STDERR
|
||||
fprintf (stderr, "%s: RTC time is localtime\n", getprogname ());
|
||||
#endif
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* HAVE_LINUX_RTC_H */
|
||||
@@ -1,53 +0,0 @@
|
||||
#!/bin/bash -
|
||||
# libguestfs virt-p2v test script
|
||||
# Copyright (C) 2015 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 virt-p2v command line parsing in non-GUI mode.
|
||||
|
||||
set -e
|
||||
|
||||
$TEST_FUNCTIONS
|
||||
skip_if_skipped
|
||||
|
||||
out=test-virt-p2v-cmdline.out
|
||||
rm -f $out
|
||||
|
||||
# The Linux kernel command line.
|
||||
$VG virt-p2v --cmdline='p2v.server=localhost p2v.port=123 p2v.username=user p2v.password=secret p2v.skip_test_connection p2v.name=test p2v.vcpus=4 p2v.memory=1G p2v.disks=sda,sdb,sdc p2v.removable=sdd p2v.interfaces=eth0,eth1 p2v.o=local p2v.oa=sparse p2v.oc=qemu:///session p2v.of=raw p2v.os=/var/tmp p2v.network=em1:wired,other p2v.dump_config_and_exit' > $out
|
||||
|
||||
# For debugging purposes.
|
||||
cat $out
|
||||
|
||||
# Check the output contains what we expect.
|
||||
grep "^remote\.server.*localhost" $out
|
||||
grep "^remote\.port.*123" $out
|
||||
grep "^auth\.username.*user" $out
|
||||
grep "^auth\.sudo.*false" $out
|
||||
grep "^guestname.*test" $out
|
||||
grep "^vcpus.*4" $out
|
||||
grep "^memory.*"$((1024*1024*1024)) $out
|
||||
grep "^disks.*sda sdb sdc" $out
|
||||
grep "^removable.*sdd" $out
|
||||
grep "^interfaces.*eth0 eth1" $out
|
||||
grep "^network_map.*em1:wired other" $out
|
||||
grep "^output\.type.*local" $out
|
||||
grep "^output\.allocation.*sparse" $out
|
||||
grep "^output\.connection.*qemu:///session" $out
|
||||
grep "^output\.format.*raw" $out
|
||||
grep "^output\.storage.*/var/tmp" $out
|
||||
|
||||
rm $out
|
||||
@@ -1,24 +0,0 @@
|
||||
#!/bin/bash -
|
||||
# libguestfs
|
||||
# Copyright (C) 2016 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.
|
||||
|
||||
set -e
|
||||
|
||||
$TEST_FUNCTIONS
|
||||
skip_if_skipped
|
||||
|
||||
$top_srcdir/podcheck.pl $srcdir/virt-p2v.pod virt-p2v
|
||||
@@ -1,59 +0,0 @@
|
||||
#!/bin/bash -
|
||||
# libguestfs virt-p2v test script
|
||||
# Copyright (C) 2014-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 virt-p2v in non-GUI mode using nbdkit instead of qemu-nbd.
|
||||
|
||||
set -e
|
||||
|
||||
$TEST_FUNCTIONS
|
||||
skip_if_skipped
|
||||
skip_if_backend uml
|
||||
skip_unless nbdkit file --version
|
||||
skip_unless test -f fedora.img
|
||||
skip_unless test -f blank-part.img
|
||||
|
||||
f1="$abs_builddir/fedora.img"
|
||||
f2="$abs_builddir/blank-part.img"
|
||||
|
||||
d=test-virt-p2v-nbdkit.d
|
||||
rm -rf $d
|
||||
mkdir $d
|
||||
|
||||
# We don't want the program under test to run real 'ssh' or 'scp'.
|
||||
# They won't work. Therefore create dummy 'ssh' and 'scp' binaries.
|
||||
pushd $d
|
||||
ln -sf "$abs_srcdir/test-virt-p2v-ssh.sh" ssh
|
||||
ln -sf "$abs_srcdir/test-virt-p2v-scp.sh" scp
|
||||
popd
|
||||
export PATH=$d:$PATH
|
||||
|
||||
# Note that the PATH already contains the local virt-p2v & virt-v2v
|
||||
# binaries under test (because of the ./run script).
|
||||
|
||||
# The Linux kernel command line.
|
||||
cmdline="p2v.server=localhost p2v.name=fedora p2v.disks=$f1,$f2 p2v.o=local p2v.os=$(pwd)/$d p2v.network=em1:wired,other p2v.post="
|
||||
|
||||
# Only use nbdkit, disable qemu-nbd.
|
||||
$VG virt-p2v --cmdline="$cmdline" --nbd=nbdkit,nbdkit-no-sa
|
||||
|
||||
# Test the libvirt XML metadata and a disk was created.
|
||||
test -f $d/fedora.xml
|
||||
test -f $d/fedora-sda
|
||||
test -f $d/fedora-sdb
|
||||
|
||||
rm -r $d
|
||||
@@ -1,96 +0,0 @@
|
||||
#!/bin/bash -
|
||||
# libguestfs virt-p2v test script
|
||||
# Copyright (C) 2014-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 virt-p2v in non-GUI mode with something resembling the
|
||||
# PXE boot code path. This tests:
|
||||
# * virt-p2v-make-disk
|
||||
# * systemd p2v.service
|
||||
# * launch-virt-p2v
|
||||
# * networking
|
||||
# * virt-p2v in kernel command-line mode
|
||||
|
||||
set -e
|
||||
|
||||
$TEST_FUNCTIONS
|
||||
slow_test
|
||||
skip_if_skipped
|
||||
skip_if_backend uml
|
||||
skip_unless_arch x86_64
|
||||
|
||||
qemu=qemu-system-x86_64
|
||||
skip_unless $qemu -help
|
||||
|
||||
img="test-virt-p2v-pxe.img"
|
||||
if ! test -f $img; then
|
||||
echo "$0: test skipped because $img was not created"
|
||||
exit 77
|
||||
fi
|
||||
|
||||
skip_unless test -f fedora.img
|
||||
f="$abs_builddir/fedora.img"
|
||||
|
||||
d=test-virt-p2v-pxe.d
|
||||
rm -rf $d
|
||||
mkdir $d
|
||||
|
||||
# Start the ssh server. Kill it if the script exits for any reason.
|
||||
# Note you must use an absolute path to exec sshd.
|
||||
`which sshd` -f test-virt-p2v-pxe.sshd_config -D -e &
|
||||
sshd_pid=$!
|
||||
cleanup ()
|
||||
{
|
||||
kill $sshd_pid
|
||||
}
|
||||
trap cleanup INT QUIT TERM EXIT ERR
|
||||
|
||||
# Get the randomly assigned sshd port number.
|
||||
port="$(grep ^Port test-virt-p2v-pxe.sshd_config | awk '{print $2}')"
|
||||
|
||||
# Connect as the local user.
|
||||
username="$(id -un)"
|
||||
|
||||
# Output storage path.
|
||||
os="$(cd $d; pwd)"
|
||||
|
||||
# The Linux kernel command line.
|
||||
cmdline="root=/dev/sda4 ro console=ttyS0 printk.time=1 p2v.server=10.0.2.2 p2v.port=$port p2v.username=$username p2v.identity=file:///var/tmp/id_rsa p2v.name=fedora p2v.o=local p2v.os=$os"
|
||||
|
||||
# Run virt-p2v inside qemu.
|
||||
$qemu \
|
||||
-no-user-config \
|
||||
-display none \
|
||||
-machine accel=kvm:tcg \
|
||||
-m 2048 \
|
||||
-kernel test-virt-p2v-pxe.vmlinuz \
|
||||
-initrd test-virt-p2v-pxe.initramfs \
|
||||
-append "$cmdline" \
|
||||
-boot c \
|
||||
-device virtio-scsi-pci,id=scsi \
|
||||
-drive file=$img,format=raw,snapshot=on,if=none,index=0,id=hd0 \
|
||||
-device scsi-hd,drive=hd0 \
|
||||
-drive file=$f,format=raw,snapshot=on,if=none,index=1,id=hd1 \
|
||||
-device scsi-hd,drive=hd1 \
|
||||
-netdev user,id=usernet \
|
||||
-device virtio-net-pci,netdev=usernet \
|
||||
-serial stdio
|
||||
|
||||
# Test the libvirt XML metadata and a disk was created.
|
||||
test -f $d/fedora.xml
|
||||
test -f $d/fedora-sda
|
||||
|
||||
rm -r $d
|
||||
@@ -1,43 +0,0 @@
|
||||
# libguestfs virt-p2v test script
|
||||
# Copyright (C) 2014-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.
|
||||
|
||||
# Minimal sshd_config used by test-virt-p2v-pxe.ssh when it runs
|
||||
# a captive sshd.
|
||||
#
|
||||
# This file is processed by awk. See p2v/Makefile.am.
|
||||
|
||||
# Choose a random high port number.
|
||||
Port __RANDOM_PORT__
|
||||
|
||||
# Only allow connections from loopback.
|
||||
ListenAddress [::1]
|
||||
ListenAddress 127.0.0.1
|
||||
|
||||
# Privilege separation breaks non-root usage of sshd.
|
||||
UsePrivilegeSeparation no
|
||||
|
||||
# Use local files instead of inaccessible global configuration.
|
||||
PidFile __abs_builddir__/test-virt-p2v-pxe.sshd.pid
|
||||
HostKey __abs_builddir__/test-virt-p2v-pxe.ssh_host_rsa_key
|
||||
|
||||
AuthorizedKeysFile __abs_builddir__/test-virt-p2v-pxe.authorized_keys
|
||||
|
||||
# Don't check file permissions.
|
||||
StrictModes no
|
||||
|
||||
# Allow the environment to be set in the authorized_keys file above.
|
||||
PermitUserEnvironment yes
|
||||
@@ -1,62 +0,0 @@
|
||||
#!/bin/bash -
|
||||
# Copyright (C) 2014-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.
|
||||
|
||||
# This is an scp substitute used by test-virt-p2v.sh.
|
||||
|
||||
TEMP=`getopt \
|
||||
-o 'o:P:' \
|
||||
-- "$@"`
|
||||
if [ $? != 0 ]; then
|
||||
echo "$0: problem parsing the command line arguments"
|
||||
exit 1
|
||||
fi
|
||||
eval set -- "$TEMP"
|
||||
|
||||
while true ; do
|
||||
case "$1" in
|
||||
# Regular arguments that we can just ignore.
|
||||
-o|-P)
|
||||
shift 2
|
||||
;;
|
||||
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
echo "$0: internal error ($1)"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Hopefully there are >= two arguments left, the source (local)
|
||||
# file(s) and a remote file of the form user@server:remote.
|
||||
if [ $# -lt 2 ]; then
|
||||
echo "$0: incorrect number of arguments found:" "$@"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# https://stackoverflow.com/questions/1853946/getting-the-last-argument-passed-to-a-shell-script/1854031#1854031
|
||||
remote="${@: -1}"
|
||||
# https://stackoverflow.com/questions/20398499/remove-last-argument-from-argument-list-of-shell-script-bash/26163980#26163980
|
||||
set -- "${@:1:$(($#-1))}"
|
||||
|
||||
remote="$(echo $remote | awk -F: '{print $2}')"
|
||||
|
||||
# Use the copy command.
|
||||
exec cp "$@" "$remote"
|
||||
@@ -1,61 +0,0 @@
|
||||
#!/bin/bash -
|
||||
# Copyright (C) 2014 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.
|
||||
|
||||
# This is an ssh substitute used by test-virt-p2v.sh.
|
||||
|
||||
TEMP=`getopt \
|
||||
-o 'l:No:p:R:' \
|
||||
-- "$@"`
|
||||
if [ $? != 0 ]; then
|
||||
echo "$0: problem parsing the command line arguments"
|
||||
exit 1
|
||||
fi
|
||||
eval set -- "$TEMP"
|
||||
|
||||
while true ; do
|
||||
case "$1" in
|
||||
# Regular arguments that we can just ignore.
|
||||
-N)
|
||||
shift
|
||||
;;
|
||||
-l|-o|-p)
|
||||
shift 2
|
||||
;;
|
||||
|
||||
# ssh -R 0:localhost:<port> (port forwarding). Don't actually
|
||||
# port forward, just return the original port number here so that
|
||||
# the conversion process connects directly to qemu-nbd.
|
||||
-R)
|
||||
arg="$2"
|
||||
port="$(echo $arg | awk -F: '{print $3}')"
|
||||
echo "Allocated port" $port "for remote forward"
|
||||
shift 2
|
||||
;;
|
||||
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
echo "$0: internal error ($1)"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Now run the interactive shell.
|
||||
exec bash
|
||||
@@ -1,57 +0,0 @@
|
||||
#!/bin/bash -
|
||||
# libguestfs virt-p2v test script
|
||||
# Copyright (C) 2014 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 virt-p2v in non-GUI mode.
|
||||
|
||||
set -e
|
||||
|
||||
$TEST_FUNCTIONS
|
||||
skip_if_skipped
|
||||
skip_if_backend uml
|
||||
skip_unless test -f fedora.img
|
||||
skip_unless test -f blank-part.img
|
||||
|
||||
f1="$abs_builddir/fedora.img"
|
||||
f2="$abs_builddir/blank-part.img"
|
||||
|
||||
d=test-virt-p2v.d
|
||||
rm -rf $d
|
||||
mkdir $d
|
||||
|
||||
# We don't want the program under test to run real 'ssh' or 'scp'.
|
||||
# They won't work. Therefore create dummy 'ssh' and 'scp' binaries.
|
||||
pushd $d
|
||||
ln -sf "$abs_srcdir/test-virt-p2v-ssh.sh" ssh
|
||||
ln -sf "$abs_srcdir/test-virt-p2v-scp.sh" scp
|
||||
popd
|
||||
export PATH=$d:$PATH
|
||||
|
||||
# Note that the PATH already contains the local virt-p2v & virt-v2v
|
||||
# binaries under test (because of the ./run script).
|
||||
|
||||
# The Linux kernel command line.
|
||||
cmdline="p2v.server=localhost p2v.name=fedora p2v.disks=$f1,$f2 p2v.o=local p2v.os=$(pwd)/$d p2v.network=em1:wired,other p2v.post="
|
||||
|
||||
$VG virt-p2v --cmdline="$cmdline"
|
||||
|
||||
# Test the libvirt XML metadata and a disk was created.
|
||||
test -f $d/fedora.xml
|
||||
test -f $d/fedora-sda
|
||||
test -f $d/fedora-sdb
|
||||
|
||||
rm -r $d
|
||||
256
p2v/utils.c
256
p2v/utils.c
@@ -1,256 +0,0 @@
|
||||
/* virt-p2v
|
||||
* Copyright (C) 2015 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <locale.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "ignore-value.h"
|
||||
|
||||
#include "p2v.h"
|
||||
|
||||
#define CHOMP(line,len) \
|
||||
do { \
|
||||
if ((len) > 0 && (line)[(len)-1] == '\n') { \
|
||||
(line)[(len)-1] = '\0'; \
|
||||
len--; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Return size of a block device, from F</sys/block/I<dev>/size>.
|
||||
*
|
||||
* This function always succeeds, or else exits (since we expect
|
||||
* C<dev> to always be valid and the C<size> file to always exist).
|
||||
*/
|
||||
uint64_t
|
||||
get_blockdev_size (const char *dev)
|
||||
{
|
||||
CLEANUP_FCLOSE FILE *fp = NULL;
|
||||
CLEANUP_FREE char *path = NULL;
|
||||
CLEANUP_FREE char *size_str = NULL;
|
||||
size_t len;
|
||||
uint64_t size;
|
||||
|
||||
if (asprintf (&path, "/sys/block/%s/size", dev) == -1)
|
||||
error (EXIT_FAILURE, errno, "asprintf");
|
||||
|
||||
fp = fopen (path, "r");
|
||||
if (fp == NULL)
|
||||
error (EXIT_FAILURE, errno, "fopen: %s", path);
|
||||
if (getline (&size_str, &len, fp) == -1)
|
||||
error (EXIT_FAILURE, errno, "getline: %s", path);
|
||||
|
||||
if (sscanf (size_str, "%" SCNu64, &size) != 1)
|
||||
error (EXIT_FAILURE, 0, "cannot parse %s: %s", path, size_str);
|
||||
|
||||
size /= 2*1024*1024; /* size from kernel is given in sectors? */
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return model of a block device, from F</sys/block/I<dev>/device/model>.
|
||||
*
|
||||
* Returns C<NULL> if the file was not found. The caller must
|
||||
* free the returned string.
|
||||
*/
|
||||
char *
|
||||
get_blockdev_model (const char *dev)
|
||||
{
|
||||
CLEANUP_FCLOSE FILE *fp = NULL;
|
||||
CLEANUP_FREE char *path = NULL;
|
||||
char *model = NULL;
|
||||
size_t len = 0;
|
||||
ssize_t n;
|
||||
|
||||
if (asprintf (&path, "/sys/block/%s/device/model", dev) == -1)
|
||||
error (EXIT_FAILURE, errno, "asprintf");
|
||||
fp = fopen (path, "r");
|
||||
if (fp == NULL) {
|
||||
perror (path);
|
||||
return NULL;
|
||||
}
|
||||
if ((n = getline (&model, &len, fp)) == -1) {
|
||||
perror (path);
|
||||
free (model);
|
||||
return NULL;
|
||||
}
|
||||
CHOMP (model, n);
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the serial number of a block device.
|
||||
*
|
||||
* This is found using the lsblk command.
|
||||
*
|
||||
* Returns C<NULL> if we could not get the serial number. The caller
|
||||
* must free the returned string.
|
||||
*/
|
||||
char *
|
||||
get_blockdev_serial (const char *dev)
|
||||
{
|
||||
CLEANUP_PCLOSE FILE *fp = NULL;
|
||||
CLEANUP_FREE char *cmd = NULL;
|
||||
char *serial = NULL;
|
||||
size_t len = 0;
|
||||
ssize_t n;
|
||||
|
||||
if (asprintf (&cmd, "lsblk -o serial /dev/%s --nodeps --noheadings",
|
||||
dev) == -1)
|
||||
error (EXIT_FAILURE, errno, "asprintf");
|
||||
fp = popen (cmd, "r");
|
||||
if (fp == NULL) {
|
||||
perror (cmd);
|
||||
return NULL;
|
||||
}
|
||||
if ((n = getline (&serial, &len, fp)) == -1) {
|
||||
perror (cmd);
|
||||
free (serial);
|
||||
return NULL;
|
||||
}
|
||||
CHOMP (serial, n);
|
||||
return serial;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return contents of F</sys/class/net/I<if_name>/address> (if found).
|
||||
*/
|
||||
char *
|
||||
get_if_addr (const char *if_name)
|
||||
{
|
||||
CLEANUP_FCLOSE FILE *fp = NULL;
|
||||
CLEANUP_FREE char *path = NULL;
|
||||
char *content = NULL;
|
||||
size_t len = 0;
|
||||
ssize_t n;
|
||||
|
||||
if (asprintf (&path, "/sys/class/net/%s/address", if_name) == -1)
|
||||
error (EXIT_FAILURE, errno, "asprintf");
|
||||
fp = fopen (path, "r");
|
||||
if (fp == NULL)
|
||||
return NULL;
|
||||
if ((n = getline (&content, &len, fp)) == -1) {
|
||||
perror (path);
|
||||
free (content);
|
||||
return NULL;
|
||||
}
|
||||
CHOMP (content, n);
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return contents of F</sys/class/net/I<if_name>/device/vendor> (if
|
||||
* found), mapped to the PCI vendor. See:
|
||||
* L<http://pjwelsh.blogspot.co.uk/2011/11/howto-get-network-card-vendor-device-or.html>
|
||||
*/
|
||||
char *
|
||||
get_if_vendor (const char *if_name, int truncate)
|
||||
{
|
||||
CLEANUP_FCLOSE FILE *fp = NULL;
|
||||
CLEANUP_FREE char *path = NULL;
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
ssize_t n;
|
||||
char vendor[5];
|
||||
|
||||
if (asprintf (&path, "/sys/class/net/%s/device/vendor", if_name) == -1)
|
||||
error (EXIT_FAILURE, errno, "asprintf");
|
||||
fp = fopen (path, "r");
|
||||
if (fp == NULL) {
|
||||
perror (path);
|
||||
return NULL;
|
||||
}
|
||||
if ((n = getline (&line, &len, fp)) == -1) {
|
||||
perror (path);
|
||||
free (line);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Vendor is (always?) a 16 bit quantity (as defined by PCI),
|
||||
* something like "0x8086" (for Intel Corp).
|
||||
*/
|
||||
CHOMP (line, n);
|
||||
if (line[0] != '0' || line[1] != 'x' || strlen (&line[2]) != 4) {
|
||||
free (line);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy (vendor, &line[2]);
|
||||
|
||||
fclose (fp);
|
||||
fp = fopen ("/usr/share/hwdata/pci.ids", "r");
|
||||
if (fp == NULL) {
|
||||
perror ("/usr/share/hwdata/pci.ids");
|
||||
free (line);
|
||||
return NULL;
|
||||
}
|
||||
while ((n = getline (&line, &len, fp)) != -1) {
|
||||
CHOMP (line, n);
|
||||
if (STRPREFIX (line, vendor)) {
|
||||
/* Find the start of the name after the vendor ID and whitespace. */
|
||||
size_t i = 4;
|
||||
n -= 4;
|
||||
|
||||
while (n > 0 && isspace (line[i])) {
|
||||
i++;
|
||||
n--;
|
||||
}
|
||||
|
||||
memmove (&line[0], &line[i], n+1 /* copy trailing \0 */);
|
||||
|
||||
/* Truncate? */
|
||||
if (truncate > 0 && n > truncate)
|
||||
line[n] = '\0';
|
||||
|
||||
return line;
|
||||
}
|
||||
}
|
||||
|
||||
free (line);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* XXX We could make this configurable. */
|
||||
#define NETWORK_ONLINE_COMMAND "nm-online -t 30"
|
||||
|
||||
/**
|
||||
* Wait for the network to come online, but don't error out if that
|
||||
* fails. The caller will call C<test_connection> immediately after
|
||||
* this which will fail if the network didn't come online.
|
||||
*/
|
||||
void
|
||||
wait_network_online (const struct config *config)
|
||||
{
|
||||
#ifdef DEBUG_STDERR
|
||||
fprintf (stderr, "waiting for the network to come online ...\n");
|
||||
fprintf (stderr, "%s\n", NETWORK_ONLINE_COMMAND);
|
||||
fflush (stderr);
|
||||
#endif
|
||||
|
||||
ignore_value (system (NETWORK_ONLINE_COMMAND));
|
||||
}
|
||||
@@ -1,267 +0,0 @@
|
||||
#!/bin/bash -
|
||||
# @configure_input@
|
||||
# virt-p2v-make-disk
|
||||
# Copyright (C) 2014-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.
|
||||
|
||||
unset CDPATH
|
||||
|
||||
program="virt-p2v-make-disk"
|
||||
version="@PACKAGE_VERSION@"
|
||||
|
||||
if [ -n "$VIRT_P2V_DATA_DIR" ]; then
|
||||
datadir="$VIRT_P2V_DATA_DIR"
|
||||
libdir="$VIRT_P2V_DATA_DIR"
|
||||
else
|
||||
datadir="@datadir@/virt-p2v"
|
||||
libdir="@libdir@/virt-p2v"
|
||||
fi
|
||||
|
||||
# Parse the command line arguments.
|
||||
shortopts=o:vV
|
||||
longopts=arch:,help,short-options,inject-ssh-identity:,install:,long-options,no-warn-if-partition,output:,verbose,version
|
||||
TEMP=`getopt \
|
||||
-o "$shortopts" \
|
||||
--long "$longopts" \
|
||||
-n $program -- "$@"`
|
||||
if [ $? != 0 ]; then
|
||||
echo "$program: problem parsing the command line arguments"
|
||||
exit 1
|
||||
fi
|
||||
eval set -- "$TEMP"
|
||||
|
||||
output=
|
||||
upload=
|
||||
verbose=
|
||||
declare -a passthru
|
||||
|
||||
usage ()
|
||||
{
|
||||
echo "Usage:"
|
||||
echo " $program [--options] -o /dev/sdX [os-version]"
|
||||
echo
|
||||
echo "Read $program(1) man page for more information."
|
||||
exit $1
|
||||
}
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
--arch)
|
||||
arch="$2"
|
||||
shift 2;;
|
||||
--inject-ssh-identity)
|
||||
upload="--upload $2:/var/tmp/id_rsa"
|
||||
shift 2;;
|
||||
-o|--output)
|
||||
output="$2"
|
||||
shift 2;;
|
||||
-v|--verbose)
|
||||
set +x
|
||||
verbose=1
|
||||
shift;;
|
||||
|
||||
# virt-builder parameters that are passed through.
|
||||
--install)
|
||||
passthru[${#passthru[*]}]="$1"
|
||||
passthru[${#passthru[*]}]="$2"
|
||||
shift 2;;
|
||||
|
||||
--no-warn-if-partition)
|
||||
passthru[${#passthru[*]}]="$1"
|
||||
shift;;
|
||||
|
||||
# help etc.
|
||||
--help)
|
||||
usage 0;;
|
||||
-V|--version)
|
||||
echo "$program $version"
|
||||
exit 0;;
|
||||
--short-options)
|
||||
echo -n "$shortopts" |
|
||||
@SED@ -e 's/://g' -e 's/\(.\)/-\1\n/g'
|
||||
exit 0;;
|
||||
--long-options)
|
||||
echo "$longopts" |
|
||||
@SED@ -e 's/,/\n/g' -e 's/:$//mg' -e 's/\(.*\)/--\1/mg' |
|
||||
grep -v -E -- "--(short|long)-options"
|
||||
exit 0;;
|
||||
--)
|
||||
shift
|
||||
break;;
|
||||
*)
|
||||
echo "internal error ($1)"
|
||||
exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$output" ]; then
|
||||
echo "$program: You must set the -o (--output) option."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $# -gt 1 ]; then
|
||||
echo "$program: Too many parameters. See $program(1)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $# -eq 1 ]; then
|
||||
osversion="$1"
|
||||
else
|
||||
# If osversion was not set, then we must guess a good value
|
||||
# based on the host distro.
|
||||
if test -f /etc/os-release; then
|
||||
osversion="`. /etc/os-release && echo ${ID}-${VERSION_ID}`"
|
||||
fi
|
||||
if [ "x$osversion" = "x" ]; then
|
||||
echo "$program: unable to guess a suitable os-version."
|
||||
echo "You must supply one on the command line and output of 'virt-builder -l'."
|
||||
echo "See $program(1) for further details."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$arch" ]; then
|
||||
arch_option="--arch $arch"
|
||||
virt_p2v_xz_binary="$libdir/virt-p2v.$arch.xz"
|
||||
else
|
||||
virt_p2v_xz_binary="$libdir/virt-p2v.xz"
|
||||
fi
|
||||
|
||||
if [ ! -f "$virt_p2v_xz_binary" ]; then
|
||||
echo "$program: cannot find $virt_p2v_xz_binary"
|
||||
if [ -n "$arch" ]; then
|
||||
echo "You used the '--arch' option, so it’s likely that you will need to build"
|
||||
echo "a virt-p2v.$arch binary yourself."
|
||||
echo "See guestfs-building(1) section BUILDING i686 32 BIT VIRT-P2V for help."
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create a temporary directory and clean it up when we finish.
|
||||
tmpdir="$(mktemp -d)"
|
||||
cleanup ()
|
||||
{
|
||||
rm -rf $tmpdir
|
||||
}
|
||||
trap cleanup INT QUIT TERM EXIT ERR
|
||||
|
||||
# Uncompress the virt-p2v binary into tmpdir.
|
||||
virt_p2v_binary="$tmpdir/virt-p2v"
|
||||
xzcat "$virt_p2v_xz_binary" > "$virt_p2v_binary"
|
||||
|
||||
# Variations depending on the target distro. The main difference
|
||||
# is in the list of distro packages we add to the base appliance.
|
||||
case "$osversion" in
|
||||
centos-*|fedora-*|rhel-*|scientificlinux-*|oraclelinux-*)
|
||||
depsfile="$datadir/dependencies.redhat"
|
||||
cat > $tmpdir/p2v.conf <<'EOF'
|
||||
add_drivers+=" usb-storage "
|
||||
EOF
|
||||
cat > $tmpdir/post-install <<'EOF'
|
||||
#!/bin/bash
|
||||
# Rebuild the initramfs.
|
||||
latest_version="$(cd /lib/modules; ls -1vr | head -1)"
|
||||
dracut -v -f --kver $latest_version
|
||||
EOF
|
||||
# Double quotes because we want $tmpdir to be expanded:
|
||||
extra_args="
|
||||
--selinux-relabel
|
||||
--upload $tmpdir/p2v.conf:/etc/dracut.conf.d/
|
||||
--run $tmpdir/post-install
|
||||
"
|
||||
;;
|
||||
debian-*|ubuntu-*)
|
||||
depsfile="$datadir/dependencies.debian"
|
||||
cat > $tmpdir/policy-rc.d <<'EOF'
|
||||
#!/bin/sh
|
||||
# Avoid running daemons during the upgrade/installation
|
||||
exit 101
|
||||
EOF
|
||||
chmod +x $tmpdir/policy-rc.d
|
||||
# Double quotes because we want $tmpdir to be expanded:
|
||||
preinstall_args="
|
||||
--upload $tmpdir/policy-rc.d:/usr/sbin/policy-rc.d
|
||||
"
|
||||
final_args="
|
||||
--delete /usr/sbin/policy-rc.d
|
||||
"
|
||||
;;
|
||||
archlinux-*)
|
||||
depsfile="$datadir/dependencies.archlinux"
|
||||
;;
|
||||
opensuse-*|suse-*)
|
||||
depsfile="$datadir/dependencies.suse"
|
||||
;;
|
||||
*)
|
||||
echo "$program: internal error: could not work out the Linux distro from '$osversion'"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
# Virt-builder requires the dependencies to be comma-separated with
|
||||
# no spaces. The $depsfile is one dependency per line.
|
||||
if [ ! -f "$depsfile" ]; then
|
||||
echo "$program: cannot find dependencies file ($depsfile)"
|
||||
exit 1
|
||||
fi
|
||||
install=
|
||||
while read line; do
|
||||
if [ -n "$line" ]; then
|
||||
if [ -z "$install" ]; then
|
||||
install="$line"
|
||||
else
|
||||
install="$install,$line"
|
||||
fi
|
||||
fi
|
||||
done < $depsfile
|
||||
|
||||
# Add -v -x if we're in verbose mode.
|
||||
if [ "x$verbose" = "x1" ]; then
|
||||
verbose_option="-v -x"
|
||||
fi
|
||||
|
||||
# Run virt-builder. Note we controversially assume systemd here. We
|
||||
# could provide a sysvinit fallback if required.
|
||||
virt-builder "$osversion" \
|
||||
$verbose_option \
|
||||
--output "$output" \
|
||||
$arch_option \
|
||||
$preinstall_args \
|
||||
--update \
|
||||
--install "$install" \
|
||||
--root-password password:p2v \
|
||||
--upload "$datadir"/issue:/etc/issue \
|
||||
--upload "$datadir"/issue:/etc/issue.net \
|
||||
--mkdir /usr/bin \
|
||||
--upload "$virt_p2v_binary":/usr/bin/virt-p2v \
|
||||
--chmod 0755:/usr/bin/virt-p2v \
|
||||
--upload "$datadir"/launch-virt-p2v:/usr/bin/ \
|
||||
--chmod 0755:/usr/bin/launch-virt-p2v \
|
||||
--upload "$datadir"/p2v.service:/etc/systemd/system/ \
|
||||
--mkdir /etc/systemd/system/multi-user.target.wants \
|
||||
--link /etc/systemd/system/p2v.service:/etc/systemd/system/multi-user.target.wants/p2v.service \
|
||||
--edit '/lib/systemd/system/getty@.service:
|
||||
s/^ExecStart=(.*)/ExecStart=$1 -a root/
|
||||
' \
|
||||
--edit '/etc/systemd/logind.conf:
|
||||
s/^[Login]/[Login]\nReserveVT=1\n/
|
||||
' \
|
||||
$upload \
|
||||
$extra_args \
|
||||
"${passthru[@]}" \
|
||||
$final_args
|
||||
|
||||
# We have to do this so the cleanup() handler runs.
|
||||
exit $?
|
||||
@@ -1,218 +0,0 @@
|
||||
=head1 NAME
|
||||
|
||||
virt-p2v-make-disk - Build the virt-p2v disk using virt-builder
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
virt-p2v-make-disk -o /dev/sdX [os-version]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<virt-p2v(1)> converts a physical machine to run virtualized on KVM,
|
||||
managed by libvirt, OpenStack, oVirt, Red Hat Enterprise
|
||||
Virtualisation (RHEV), or one of the other targets supported by
|
||||
L<virt-v2v(1)>.
|
||||
|
||||
virt-p2v-make-disk is a script which creates a bootable disk image or
|
||||
USB key containing virt-p2v. It uses L<virt-builder(1)> to do this,
|
||||
and is just a small shell script around virt-builder.
|
||||
|
||||
The required I<-o> parameter specifies where the output should go, for
|
||||
example to a USB key (eg. C<-o /dev/sdX>) or to a file. If you pass a
|
||||
device name, then B<the existing contents of the device will be erased>.
|
||||
|
||||
=head2 C<os-version> parameter
|
||||
|
||||
The optional C<os-version> parameter is the base Linux distro to use
|
||||
for the operating system on the ISO. If you don't set this parameter,
|
||||
the script tries to choose a suitable default for you. Most users
|
||||
should I<not> use the C<os-version> parameter.
|
||||
|
||||
The base OS selected for virt-p2v is not related in any way to the OS
|
||||
of the physical machine that you are trying to convert.
|
||||
|
||||
To list possible C<os-version> combinations, do:
|
||||
|
||||
virt-builder -l
|
||||
|
||||
=head1 EXAMPLES
|
||||
|
||||
Write a virt-p2v bootable USB key on F</dev/sdX> (any existing content
|
||||
on F</dev/sdX> is erased):
|
||||
|
||||
virt-p2v-make-disk -o /dev/sdX
|
||||
|
||||
Write a virt-p2v bootable virtual disk image, and boot it under qemu:
|
||||
|
||||
virt-p2v-make-disk -o /var/tmp/p2v.img
|
||||
qemu-kvm -m 1024 -boot c \
|
||||
-drive file=/var/tmp/p2v.img,if=virtio,index=0 \
|
||||
-drive file=/var/tmp/guest.img,if=virtio,index=1
|
||||
|
||||
where F</var/tmp/guest.img> would be the disk image of some guest that
|
||||
you want to convert (for testing only).
|
||||
|
||||
=head1 ADDING EXTRA PACKAGES
|
||||
|
||||
You can install extra packages using the I<--install> option. This
|
||||
can be useful for making a more fully-featured virt-p2v disk with
|
||||
extra tools for debugging and troubleshooting. Give a list of
|
||||
packages, separated by commas. For example:
|
||||
|
||||
virt-p2v-make-disk -o /var/tmp/p2v.img --install tcpdump,traceroute
|
||||
|
||||
=head1 ADDING AN SSH IDENTITY
|
||||
|
||||
You can inject an SSH identity (private key) file to the image using
|
||||
the I<--inject-ssh-identity> option.
|
||||
|
||||
First create a key pair. It must have an empty passphrase:
|
||||
|
||||
ssh-keygen -t rsa -N '' -f id_rsa
|
||||
|
||||
This creates a private key (C<id_rsa>) and a public key
|
||||
(C<id_rsa.pub>) pair. The public key should be appended to the
|
||||
C<authorized_keys> file on the virt-v2v conversion server (usually to
|
||||
C</root/.ssh/authorized_keys>).
|
||||
|
||||
The private key should be injected into the disk image and then
|
||||
discarded:
|
||||
|
||||
virt-p2v-make-disk [...] --inject-ssh-identity id_rsa
|
||||
rm id_rsa
|
||||
|
||||
When booting virt-p2v, specify the URL of the injected file like this:
|
||||
|
||||
│ User name: [root_____________________________] │
|
||||
│ │
|
||||
│ Password: [ <leave this field blank> ] │
|
||||
│ │
|
||||
│ SSH Identity URL: [file:///var/tmp/id_rsa___________] │
|
||||
|
||||
or if using the kernel command line, add:
|
||||
|
||||
p2v.identity=file:///var/tmp/id_rsa
|
||||
|
||||
For more information, see L<virt-p2v(1)/SSH IDENTITIES>.
|
||||
|
||||
=head1 32 BIT VIRT-P2V
|
||||
|
||||
For improved compatibility with older hardware, virt-p2v-make-disk has
|
||||
an I<--arch> option. The most useful setting (on x86-64 hosts) is
|
||||
I<--arch i686>, which builds a 32 bit virt-p2v environment that will
|
||||
work on older hardware. 32 bit virt-p2v can convert 64 bit physical
|
||||
machines and can interoperate with 64 bit virt-v2v and 64 bit
|
||||
hypervisors.
|
||||
|
||||
This option requires that you have built F<virt-p2v.$arch> (ie.
|
||||
usually F<virt-p2v.i686>) by some means, and that you install it next
|
||||
to the ordinary F<virt-p2v> binary (eg. in F<$libdir/virt-p2v/> or
|
||||
C<$VIRT_V2V_DATA_DIR>). This is outside the scope of this manual
|
||||
page, but you can find some tips in
|
||||
L<guestfs-building(1)/BUILDING i686 32 BIT VIRT-P2V>.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<--help>
|
||||
|
||||
Display help.
|
||||
|
||||
=item B<--arch> ARCH
|
||||
|
||||
Set the architecture of the virt-p2v ISO. See L</32 BIT VIRT-P2V> above.
|
||||
|
||||
If this option is not supplied, then the default is to use the same
|
||||
architecture as the host that is running virt-p2v-make-disk.
|
||||
|
||||
=item B<--inject-ssh-identity> id_rsa
|
||||
|
||||
Add an SSH identity (private key) file into the image.
|
||||
See L</ADDING AN SSH IDENTITY> above.
|
||||
|
||||
=item B<--install> pkg,pkg,...
|
||||
|
||||
Add extra packages to the image.
|
||||
See L</ADDING EXTRA PACKAGES> above.
|
||||
|
||||
=item B<--no-warn-if-partition>
|
||||
|
||||
Normally you should not write to a partition on a USB drive (ie. don’t
|
||||
use S<C<-o /dev/sdX1>>, use S<C<-o /dev/sdX>> to make a bootable USB
|
||||
drive). If you do this, virt-builder prints a warning. This option
|
||||
suppresses that warning.
|
||||
|
||||
=item B<-o> OUTPUT
|
||||
|
||||
=item B<--output> OUTPUT
|
||||
|
||||
Write output to C<OUTPUT>, which can be a local file or block device.
|
||||
B<The existing contents of the device will be erased>.
|
||||
|
||||
=item B<-v>
|
||||
|
||||
=item B<--verbose>
|
||||
|
||||
Enable verbose output. Use this if you need to debug problems with
|
||||
the script or if you are filing a bug.
|
||||
|
||||
=item B<-V>
|
||||
|
||||
=item B<--version>
|
||||
|
||||
Display version number and exit.
|
||||
|
||||
=back
|
||||
|
||||
=head1 FILES
|
||||
|
||||
=over 4
|
||||
|
||||
=item F<$libdir/virt-p2v/virt-p2v.xz>
|
||||
|
||||
The L<virt-p2v(1)> binary which is copied into the bootable disk
|
||||
image.
|
||||
|
||||
The location of the binary can be changed by setting the
|
||||
C<VIRT_P2V_DATA_DIR> environment variable.
|
||||
|
||||
=item F<$datadir/virt-p2v/issue>
|
||||
|
||||
=item F<$datadir/virt-p2v/launch-virt-p2v.in>
|
||||
|
||||
=item F<$datadir/virt-p2v/p2v.service>
|
||||
|
||||
Various data files that are copied into the bootable disk image.
|
||||
|
||||
The location of these files can be changed by setting the
|
||||
C<VIRT_P2V_DATA_DIR> environment variable.
|
||||
|
||||
=back
|
||||
|
||||
=head1 ENVIRONMENT VARIABLES
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<VIRT_P2V_DATA_DIR>
|
||||
|
||||
The directory where virt-p2v-make-disk looks for data files (see
|
||||
L</FILES> above). If not set, a compiled-in location is used.
|
||||
|
||||
=back
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<virt-p2v(1)>,
|
||||
L<virt-p2v-make-kickstart(1)>,
|
||||
L<virt-p2v-make-kiwi(1)>,
|
||||
L<virt-v2v(1)>,
|
||||
L<http://libguestfs.org/>.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Richard W.M. Jones L<http://people.redhat.com/~rjones/>
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (C) 2009-2019 Red Hat Inc.
|
||||
@@ -1,241 +0,0 @@
|
||||
#!/bin/bash -
|
||||
# @configure_input@
|
||||
# virt-p2v-make-kickstart
|
||||
# Copyright (C) 2014-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.
|
||||
|
||||
unset CDPATH
|
||||
|
||||
program="virt-p2v-make-kickstart"
|
||||
version="@PACKAGE_VERSION@"
|
||||
|
||||
# Parse the command line arguments.
|
||||
shortopts=o:vV
|
||||
longopts=help,inject-ssh-identity:,install:,long-options,output:,proxy:,short-options,verbose,version
|
||||
TEMP=`getopt \
|
||||
-o "$shortopts" \
|
||||
--long "$longopts" \
|
||||
-n $program -- "$@"`
|
||||
if [ $? != 0 ]; then
|
||||
echo "$program: problem parsing the command line arguments"
|
||||
exit 1
|
||||
fi
|
||||
eval set -- "$TEMP"
|
||||
|
||||
usage ()
|
||||
{
|
||||
echo "Usage:"
|
||||
echo " $program [--options] [-o p2v.ks] [--proxy=http://...] repo [repo...]"
|
||||
echo
|
||||
echo "Read $program(1) man page for more information."
|
||||
exit $1
|
||||
}
|
||||
|
||||
extra_packages=
|
||||
output=p2v.ks
|
||||
proxy=
|
||||
ssh_identity=
|
||||
verbose=
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
--inject-ssh-identity)
|
||||
ssh_identity="$2"
|
||||
shift 2;;
|
||||
--install)
|
||||
extra_packages="${extra_packages:+${extra_packages},}$2"
|
||||
shift 2;;
|
||||
-o|--output)
|
||||
output="$2"
|
||||
shift 2;;
|
||||
--proxy)
|
||||
proxy="--proxy=$2"
|
||||
shift 2;;
|
||||
--repo)
|
||||
repo="$2"
|
||||
shift 2;;
|
||||
-v|--verbose)
|
||||
set +x
|
||||
verbose=1
|
||||
shift;;
|
||||
|
||||
# help etc.
|
||||
--help)
|
||||
usage 0;;
|
||||
-V|--version)
|
||||
echo "$program $version"
|
||||
exit 0;;
|
||||
--short-options)
|
||||
echo -n "$shortopts" |
|
||||
@SED@ -e 's/://g' -e 's/\(.\)/-\1\n/g'
|
||||
exit 0;;
|
||||
--long-options)
|
||||
echo "$longopts" |
|
||||
@SED@ -e 's/,/\n/g' -e 's/:$//mg' -e 's/\(.*\)/--\1/mg' |
|
||||
grep -v -E -- "--(short|long)-options"
|
||||
exit 0;;
|
||||
--)
|
||||
shift
|
||||
break;;
|
||||
*)
|
||||
echo "internal error ($1)"
|
||||
exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "$program: Missing repo(s). See $program(1)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -e
|
||||
|
||||
if [ -n "$VIRT_P2V_DATA_DIR" ]; then
|
||||
datadir="$VIRT_P2V_DATA_DIR"
|
||||
libdir="$VIRT_P2V_DATA_DIR"
|
||||
else
|
||||
datadir="@datadir@/virt-p2v"
|
||||
libdir="@libdir@/virt-p2v"
|
||||
fi
|
||||
|
||||
# Base64-encode the files that we need to embed into the kickstart.
|
||||
base64_issue="$(base64 $datadir/issue)"
|
||||
base64_launch_virt_p2v="$(base64 $datadir/launch-virt-p2v)"
|
||||
base64_p2v_service="$(base64 $datadir/p2v.service)"
|
||||
if [ -n "$ssh_identity" ]; then
|
||||
base64_ssh_identity="$(base64 $ssh_identity)"
|
||||
else
|
||||
base64_ssh_identity=
|
||||
fi
|
||||
|
||||
# virt-p2v binary is too large unless we strip it and recompress it.
|
||||
tmpfile="$(mktemp -u)"
|
||||
xzcat $libdir/virt-p2v.xz > $tmpfile
|
||||
md5sum_virt_p2v="$(md5sum $tmpfile | @AWK@ '{print $1}')"
|
||||
strip --strip-all $tmpfile
|
||||
gzip -9 $tmpfile
|
||||
base64_virt_p2v="$(base64 $tmpfile.gz)"
|
||||
rm $tmpfile.gz
|
||||
|
||||
# Repositories.
|
||||
repos=
|
||||
i=0
|
||||
for repo in "$@"; do
|
||||
case "$repo" in
|
||||
fedora)
|
||||
repos="$repos
|
||||
repo --name=fedora --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-\$releasever\\\\&arch=\$basearch $proxy
|
||||
"
|
||||
;;
|
||||
rawhide)
|
||||
repos="$repos
|
||||
repo --name=rawhide --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=rawhide\\\\&arch=\$basearch $proxy
|
||||
"
|
||||
;;
|
||||
koji)
|
||||
repos="$repos
|
||||
repo --name=koji --baseurl=http://koji.fedoraproject.org/repos/rawhide/latest/\$basearch/ $proxy
|
||||
"
|
||||
;;
|
||||
rhel-5.*)
|
||||
minor=$( echo "$repo" | sed 's/rhel-[0-9]*\.\([0-9]*\)/\1/' )
|
||||
arch=`uname -m | sed 's/i[3456]86/i386/g'`
|
||||
baseurl=http://download.devel.redhat.com/released/RHEL-5-Server/U$minor/$arch/os/Server/
|
||||
# Neither $basearch nor --proxy work in RHEL 5 kickstarts.
|
||||
repos="$repos
|
||||
repo --name=rhel5_${minor}_server --baseurl=$baseurl
|
||||
"
|
||||
;;
|
||||
rhel-6.*)
|
||||
minor=$( echo "$repo" | sed 's/rhel-[0-9]*\.\([0-9]*\)/\1/' )
|
||||
baseurl=http://download.devel.redhat.com/released/RHEL-6/6.$minor
|
||||
# '$basearch' cannot be used in kickstart, so:
|
||||
arch=`uname -m`
|
||||
repos="$repos
|
||||
repo --name=rhel6_${minor}_server --baseurl=$baseurl/Server/$arch/os $proxy
|
||||
repo --name=rhel6_${minor}_server_optional --baseurl=$baseurl/Server/optional/$arch/os $proxy
|
||||
"
|
||||
;;
|
||||
rhel-7.*)
|
||||
minor=$( echo "$repo" | sed 's/rhel-[0-9]*\.\([0-9]*\)/\1/' )
|
||||
baseurl=http://download.devel.redhat.com/released/RHEL-7/7.$minor
|
||||
# '$basearch' cannot be used in kickstart, so:
|
||||
arch=`uname -m`
|
||||
repos="$repos
|
||||
repo --name=rhel7_${minor}_server --baseurl=$baseurl/Server/$arch/os $proxy
|
||||
repo --name=rhel7_${minor}_server_optional --baseurl=$baseurl/Server-optional/$arch/os $proxy
|
||||
"
|
||||
;;
|
||||
*)
|
||||
# A custom repo is just a URL.
|
||||
((i++)) ||:
|
||||
repos="$repos
|
||||
repo --name=custom$i --baseurl=$repo $proxy
|
||||
"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Dependencies. Since kickstart is Red Hat-specific, only include
|
||||
# dependencies.redhat here.
|
||||
depsfile="$datadir/dependencies.redhat"
|
||||
if [ ! -f "$depsfile" ]; then
|
||||
echo "$0: cannot find dependencies file ($depsfile)"
|
||||
exit 1
|
||||
fi
|
||||
dependencies=
|
||||
while read line; do
|
||||
if [ -n "$line" ]; then
|
||||
if [ -z "$dependencies" ]; then
|
||||
dependencies="$line"
|
||||
else
|
||||
dependencies="$dependencies
|
||||
$line"
|
||||
fi
|
||||
fi
|
||||
done < $depsfile
|
||||
|
||||
# Now generate the final kickstart, substituting as necessary.
|
||||
# AWK FTW!
|
||||
@AWK@ \
|
||||
-v "base64_issue=$base64_issue" \
|
||||
-v "base64_launch_virt_p2v=$base64_launch_virt_p2v" \
|
||||
-v "base64_p2v_service=$base64_p2v_service" \
|
||||
-v "base64_ssh_identity=$base64_ssh_identity" \
|
||||
-v "base64_virt_p2v=$base64_virt_p2v" \
|
||||
-v "dependencies=$dependencies" \
|
||||
-v "extra_packages=$extra_packages" \
|
||||
-v "md5sum_virt_p2v=$md5sum_virt_p2v" \
|
||||
-v "repos=$repos" \
|
||||
'{
|
||||
gsub (/__PACKAGE_NAME__/, "@PACKAGE_NAME@");
|
||||
gsub (/__PACKAGE_VERSION__/, "@PACKAGE_VERSION@");
|
||||
gsub (/__PACKAGE_VERSION_FULL__/, "@PACKAGE_VERSION_FULL@");
|
||||
gsub (/__BASE64_ISSUE__/, base64_issue);
|
||||
gsub (/__BASE64_LAUNCH_VIRT_P2V__/, base64_launch_virt_p2v);
|
||||
gsub (/__BASE64_P2V_SERVICE__/, base64_p2v_service);
|
||||
gsub (/__BASE64_SSH_IDENTITY__/, base64_ssh_identity);
|
||||
gsub (/__BASE64_VIRT_P2V__/, base64_virt_p2v);
|
||||
gsub (/__DEPENDENCIES__/, dependencies);
|
||||
gsub (/__EXTRA_PACKAGES__/, gensub (/,/, "\n", "g", extra_packages));
|
||||
gsub (/__MD5SUM_VIRT_P2V__/, md5sum_virt_p2v);
|
||||
gsub (/__REPOS__/, repos);
|
||||
print;
|
||||
}' \
|
||||
$datadir/p2v.ks.in > $output-t
|
||||
mv $output-t $output
|
||||
|
||||
echo "Kickstart file written to $output"
|
||||
@@ -1,339 +0,0 @@
|
||||
=head1 NAME
|
||||
|
||||
virt-p2v-make-kickstart - Build the virt-p2v kickstart
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
virt-p2v-make-kickstart [-o p2v.ks] [--proxy=http://...] repo [repo...]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<virt-p2v(1)> converts a physical machine to run virtualized on KVM,
|
||||
managed by libvirt, OpenStack, oVirt, Red Hat Enterprise
|
||||
Virtualisation (RHEV), or one of the other targets supported by
|
||||
L<virt-v2v(1)>.
|
||||
|
||||
Kickstart is a format used by Red Hat-derived distributions (such as
|
||||
Fedora, Red Hat Enterprise Linux, CentOS, Scientific Linux, and
|
||||
others) to describe how to make live CDs, install the distro, make
|
||||
"Spins" and so on. It is driven by a kickstart file.
|
||||
|
||||
virt-p2v-make-kickstart builds a kickstart file which can be used to
|
||||
build a bootable P2V ISO, live CD, USB key, or PXE image. This tool
|
||||
only builds the kickstart file, but this manual page describes some of
|
||||
the ways you can use the kickstart file.
|
||||
|
||||
=head1 BUILDING THE KICKSTART FILE
|
||||
|
||||
Using virt-p2v-make-kickstart is very simple:
|
||||
|
||||
virt-p2v-make-kickstart fedora
|
||||
|
||||
will build a kickstart file for Fedora. The kickstart file will be
|
||||
called F<p2v.ks> and located in the current directory.
|
||||
|
||||
The parameters are a list of one or more repositories. Some built-in
|
||||
repositories are available: C<fedora>, C<rawhide>, C<koji> or
|
||||
C<rhel-VERSION> (eg. C<rhel-7.1>). You can also use a URL as a
|
||||
parameter to point to a repository, for example:
|
||||
|
||||
virt-p2v-make-kickstart https://dl.fedoraproject.org/pub/fedora/linux/releases/21/Everything/x86_64/os/
|
||||
|
||||
To control the name of the output file, use the I<-o> parameter. To
|
||||
tell kickstart to use a proxy server or web cache to download files,
|
||||
use the I<--proxy> parameter.
|
||||
|
||||
=head1 BUILDING A LIVE CD / ISO
|
||||
|
||||
Once you have the kickstart file, you can use L<livecd-creator(8)>
|
||||
to make a live CD:
|
||||
|
||||
sudo livecd-creator p2v.ks
|
||||
|
||||
Before running this note that you should probably run
|
||||
C<livecd-creator> in a disposable virtual machine for these reasons:
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
You have to disable SELinux when running the tool.
|
||||
|
||||
=item *
|
||||
|
||||
This tool has to be run as root, and has some nasty failure modes.
|
||||
|
||||
=item *
|
||||
|
||||
You can only create the exact same Live CD distro as the host
|
||||
distro. Cross-builds will fail in strange ways (eg. RHBZ#1092327).
|
||||
|
||||
=back
|
||||
|
||||
=head1 BUILDING A FEDORA SPIN USING KOJI
|
||||
|
||||
This requires C<spin-livecd> permissions on Koji, which are not given
|
||||
out usually, even to Fedora packagers. However assuming you have been
|
||||
given these permissions (or have your own Koji instance, I guess),
|
||||
then you can do:
|
||||
|
||||
koji spin-livecd [--scratch] virt-p2v 1.XX.YY rawhide x86_64 p2v.ks
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
Add the C<--scratch> option to do a scratch build (recommended for
|
||||
testing).
|
||||
|
||||
=item *
|
||||
|
||||
C<1.XX.YY> should match the libguestfs version
|
||||
|
||||
=item *
|
||||
|
||||
Instead of C<rawhide> you can use any Koji target.
|
||||
|
||||
=back
|
||||
|
||||
=head1 BUILDING A BOOTABLE USB KEY
|
||||
|
||||
Use the L<livecd-iso-to-disk(8)> program to convert the ISO created
|
||||
above to a USB key:
|
||||
|
||||
sudo livecd-iso-to-disk livecd-p2v.iso /dev/sdX
|
||||
|
||||
=head1 BUILDING A PXE BOOT IMAGE
|
||||
|
||||
Use the C<livecd-iso-to-pxeboot> program to convert the ISO created
|
||||
above to a PXE boot image.
|
||||
|
||||
sudo livecd-iso-to-pxeboot livecd-p2v.iso
|
||||
|
||||
This creates a C<tftpboot> subdirectory under the current directory
|
||||
containing the files required to PXE boot virt-p2v:
|
||||
|
||||
$ ls -1R tftpboot/
|
||||
tftpboot/:
|
||||
initrd0.img
|
||||
pxelinux.0
|
||||
pxelinux.cfg/
|
||||
vmlinuz0
|
||||
|
||||
tftpboot/pxelinux.cfg:
|
||||
default
|
||||
|
||||
=head1 32 OR 64 BIT VIRT-P2V?
|
||||
|
||||
Virt-p2v can convert any 32 or 64 bit guest, regardless of whether
|
||||
virt-p2v itself is built as a 32 or 64 bit binary. The only
|
||||
restriction is that 64 bit virt-p2v cannot run on 32 bit hardware.
|
||||
|
||||
Old virt-p2v 0.9 was always built as a 32 bit (i686) ISO. This meant
|
||||
that the CD could be booted on any 32- or 64-bit i686 or x86-64
|
||||
hardware, and could convert any guest. The old virt-p2v ISO shipped
|
||||
by Red Hat was based on Red Hat Enterprise Linux (RHEL) 6.
|
||||
|
||||
Since RHEL 7 dropped support for 32 bit machines, current virt-p2v on
|
||||
RHEL can only be built for 64 bit. It cannot run on old 32 bit only
|
||||
hardware.
|
||||
|
||||
Fedora virt-p2v ISOs are generally built for 32 bit, so like the old
|
||||
RHEL 6-based virt-p2v 0.9 they can boot on any hardware.
|
||||
|
||||
=head1 TESTING VIRT-P2V USING QEMU
|
||||
|
||||
=head2 TESTING THE P2V ISO USING QEMU
|
||||
|
||||
You can use qemu to test-boot the P2V ISO:
|
||||
|
||||
qemu-kvm -m 1024 -hda /tmp/guest.img -cdrom /tmp/livecd-p2v.iso -boot d
|
||||
|
||||
Note that C<-hda> is the (virtual) system that you want to convert
|
||||
(for test purposes). It could be any guest type supported by
|
||||
L<virt-v2v(1)>, including Windows or Red Hat Enterprise Linux.
|
||||
|
||||
=head2 TESTING PXE SUPPORT USING QEMU
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
Unpack the tftpboot directory into F</tmp> (so it appears as
|
||||
F</tmp/tftpboot>).
|
||||
|
||||
=item *
|
||||
|
||||
Copy F<pxelinux.0> and F<ldlinux.c32> from syslinux (usually from
|
||||
F</usr/share/syslinux>) into F</tmp/tftpboot>.
|
||||
|
||||
=item *
|
||||
|
||||
Adjust the C<APPEND> line in F</tmp/tftpboot/pxelinux.cfg/default> if
|
||||
required. See L<virt-p2v(1)/KERNEL COMMAND LINE CONFIGURATION>.
|
||||
|
||||
=item *
|
||||
|
||||
Run qemu like this so that it acts as a TFTP and BOOTP server,
|
||||
emulating a netboot:
|
||||
|
||||
qemu-kvm \
|
||||
-m 4096 -hda /tmp/guest.img \
|
||||
-boot n \
|
||||
-netdev user,id=unet,tftp=/tmp/tftpboot,bootfile=/pxelinux.0 \
|
||||
-device virtio-net-pci,netdev=unet \
|
||||
-serial stdio
|
||||
|
||||
Note that this requires considerably more memory because the PXE image
|
||||
is loaded into memory. Also that qemu’s TFTP server is very slow and
|
||||
the virt-p2v PXE image is very large, so it can appear to "hang" after
|
||||
pxelinux starts up.
|
||||
|
||||
=back
|
||||
|
||||
=head1 ADDING EXTRA PACKAGES
|
||||
|
||||
You can install extra packages using the I<--install> option. This
|
||||
can be useful for making a more fully-featured virt-p2v disk with
|
||||
extra tools for debugging and troubleshooting. Give a list of
|
||||
packages, separated by commas. For example:
|
||||
|
||||
virt-p2v-make-kickstart [...] --install tcpdump,traceroute
|
||||
|
||||
=head1 ADDING AN SSH IDENTITY
|
||||
|
||||
You can inject an SSH identity (private key) file to the kickstart and
|
||||
hence into the ISO using the I<--inject-ssh-identity> option. Note
|
||||
that you I<cannot> inject a key once the ISO has been built.
|
||||
|
||||
First create a key pair. It must have an empty passphrase:
|
||||
|
||||
ssh-keygen -t rsa -N '' -f id_rsa
|
||||
|
||||
This creates a private key (C<id_rsa>) and a public key
|
||||
(C<id_rsa.pub>) pair. The public key should be appended to the
|
||||
C<authorized_keys> file on the virt-v2v conversion server (usually to
|
||||
C</root/.ssh/authorized_keys>).
|
||||
|
||||
The private key should be added to the kickstart file and then
|
||||
discarded:
|
||||
|
||||
virt-p2v-make-kickstart [...] --inject-ssh-identity id_rsa
|
||||
rm id_rsa
|
||||
|
||||
The ISO can then be built from the kickstart in the usual way (see
|
||||
above), and it will contain the embedded SSH identity
|
||||
(F</var/tmp/id_rsa>).
|
||||
|
||||
When booting virt-p2v, specify the URL of the injected file like this:
|
||||
|
||||
│ User name: [root_____________________________] │
|
||||
│ │
|
||||
│ Password: [ <leave this field blank> ] │
|
||||
│ │
|
||||
│ SSH Identity URL: [file:///var/tmp/id_rsa___________] │
|
||||
|
||||
or if using the kernel command line, add:
|
||||
|
||||
p2v.identity=file:///var/tmp/id_rsa
|
||||
|
||||
For more information, see L<virt-p2v(1)/SSH IDENTITIES>.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<--help>
|
||||
|
||||
Display help.
|
||||
|
||||
=item B<--inject-ssh-identity> id_rsa
|
||||
|
||||
Add an SSH identity (private key) file into the kickstart.
|
||||
See L</ADDING AN SSH IDENTITY> above.
|
||||
|
||||
=item B<--install> pkg,pkg,...
|
||||
|
||||
Add extra packages to the kickstart C<%packages> section.
|
||||
See L</ADDING EXTRA PACKAGES> above.
|
||||
|
||||
=item B<-o> OUTPUT
|
||||
|
||||
=item B<--output> OUTPUT
|
||||
|
||||
Write kickstart to C<OUTPUT>. If not specified, the default is
|
||||
F<p2v.ks> in the current directory.
|
||||
|
||||
=item B<--proxy> URL
|
||||
|
||||
Tell the kickstart to use a proxy server or web cache for downloads.
|
||||
|
||||
=item B<-v>
|
||||
|
||||
=item B<--verbose>
|
||||
|
||||
Enable verbose output. Use this if you need to debug problems with
|
||||
the script or if you are filing a bug.
|
||||
|
||||
=item B<-V>
|
||||
|
||||
=item B<--version>
|
||||
|
||||
Display version number and exit.
|
||||
|
||||
=back
|
||||
|
||||
=head1 FILES
|
||||
|
||||
=over 4
|
||||
|
||||
=item F<$libdir/virt-p2v/virt-p2v.xz>
|
||||
|
||||
The L<virt-p2v(1)> binary which is copied into the kickstart file.
|
||||
|
||||
The location of the binary can be changed by setting the
|
||||
C<VIRT_P2V_DATA_DIR> environment variable.
|
||||
|
||||
=item F<$datadir/virt-p2v/issue>
|
||||
|
||||
=item F<$datadir/virt-p2v/launch-virt-p2v.in>
|
||||
|
||||
=item F<$datadir/virt-p2v/p2v.ks.in>
|
||||
|
||||
=item F<$datadir/virt-p2v/p2v.service>
|
||||
|
||||
Various data files that are used to make the kickstart.
|
||||
|
||||
The location of these files can be changed by setting the
|
||||
C<VIRT_P2V_DATA_DIR> environment variable.
|
||||
|
||||
=back
|
||||
|
||||
=head1 ENVIRONMENT VARIABLES
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<VIRT_P2V_DATA_DIR>
|
||||
|
||||
The directory where virt-p2v-make-kickstart looks for data files and
|
||||
the virt-p2v binary (see L</FILES> above). If not set, a compiled-in
|
||||
location is used.
|
||||
|
||||
=back
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<virt-p2v(1)>,
|
||||
L<virt-p2v-make-disk(1)>,
|
||||
L<virt-v2v(1)>,
|
||||
L<livecd-creator(8)>,
|
||||
L<livecd-iso-to-disk(8)>,
|
||||
L<http://libguestfs.org/>.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Richard W.M. Jones L<http://people.redhat.com/~rjones/>
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (C) 2009-2019 Red Hat Inc.
|
||||
@@ -1,233 +0,0 @@
|
||||
#!/bin/bash -
|
||||
# @configure_input@
|
||||
# virt-p2v-make-kiwi
|
||||
# Copyright (C) 2016 SUSE.
|
||||
#
|
||||
# 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.
|
||||
|
||||
unset CDPATH
|
||||
|
||||
program="virt-p2v-make-kiwi"
|
||||
version="@PACKAGE_VERSION@"
|
||||
|
||||
# Parse the command line arguments.
|
||||
shortopts=o:V
|
||||
longopts=help,inject-ssh-identity:,long-options,output:,short-options,version
|
||||
TEMP=`getopt \
|
||||
-o "$shortopts" \
|
||||
--long "$longopts" \
|
||||
-n $program -- "$@"`
|
||||
if [ $? != 0 ]; then
|
||||
echo "$program: problem parsing the command line arguments"
|
||||
exit 1
|
||||
fi
|
||||
eval set -- "$TEMP"
|
||||
|
||||
usage ()
|
||||
{
|
||||
echo "Usage:"
|
||||
echo " $program [--options] [-o kiwi-folder]"
|
||||
echo
|
||||
echo "Read $program(1) man page for more information."
|
||||
exit $1
|
||||
}
|
||||
|
||||
output=p2v.kiwi
|
||||
ssh_identity=
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
--inject-ssh-identity)
|
||||
ssh_identity="$2"
|
||||
shift 2;;
|
||||
-o|--output)
|
||||
output="$2"
|
||||
shift 2;;
|
||||
|
||||
# help etc.
|
||||
--help)
|
||||
usage 0;;
|
||||
-V|--version)
|
||||
echo "$program $version"
|
||||
exit 0;;
|
||||
--short-options)
|
||||
echo -n "$shortopts" |
|
||||
@SED@ -e 's/://g' -e 's/\(.\)/-\1\n/g'
|
||||
exit 0;;
|
||||
--long-options)
|
||||
echo "$longopts" |
|
||||
@SED@ -e 's/,/\n/g' -e 's/:$//mg' -e 's/\(.*\)/--\1/mg' |
|
||||
grep -v -E -- "--(short|long)-options"
|
||||
exit 0;;
|
||||
--)
|
||||
shift
|
||||
break;;
|
||||
*)
|
||||
echo "internal error ($1)"
|
||||
exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
set -e
|
||||
|
||||
if [ -n "$VIRT_P2V_DATA_DIR" ]; then
|
||||
datadir="$VIRT_P2V_DATA_DIR"
|
||||
libdir="$VIRT_P2V_DATA_DIR"
|
||||
else
|
||||
datadir="@datadir@/virt-p2v"
|
||||
libdir="@libdir@/virt-p2v"
|
||||
fi
|
||||
|
||||
# Dependencies. Since kiwi is SUSE-specific, only include
|
||||
# dependencies.suse here.
|
||||
depsfile="$datadir/dependencies.suse"
|
||||
if [ ! -f "$depsfile" ]; then
|
||||
echo "$0: cannot find dependencies file ($depsfile)"
|
||||
exit 1
|
||||
fi
|
||||
dependencies=
|
||||
while read line; do
|
||||
if [ -n "$line" ]; then
|
||||
depname=$(echo $line | awk '{gsub(/ /, "", $0); print}')
|
||||
pkg=" <package name=\"$depname\"/>"
|
||||
if [ -z "$dependencies" ]; then
|
||||
dependencies="$pkg"
|
||||
else
|
||||
dependencies="$dependencies
|
||||
$pkg"
|
||||
fi
|
||||
fi
|
||||
done < $depsfile
|
||||
|
||||
# Compute the distro-dependent pieces for kiwi
|
||||
branding=
|
||||
release_pkg=
|
||||
base_pattern=
|
||||
kiwi_boot=
|
||||
repos=
|
||||
. /etc/os-release
|
||||
case "$NAME" in
|
||||
SLES)
|
||||
branding="SLE"
|
||||
release_pkg="sles-release"
|
||||
base_pattern="patterns-sles-Minimal"
|
||||
case "$VERSION_ID" in
|
||||
12)
|
||||
kiwi_boot="SLES12"
|
||||
repos="http://download.suse.de/ibs/SUSE:/SLE-12:/Update/standard
|
||||
http://download.suse.de/ibs/SUSE:/SLE-12:/GA/standard"
|
||||
;;
|
||||
12.1)
|
||||
kiwi_boot="SLES12"
|
||||
repos="http://download.suse.de/ibs/SUSE:/SLE-12-SP1:/Update/standard
|
||||
http://download.suse.de/ibs/SUSE:/SLE-12-SP1:/GA/standard
|
||||
http://download.suse.de/ibs/SUSE:/SLE-12:/Update/standard
|
||||
http://download.suse.de/ibs/SUSE:/SLE-12:/GA/standard"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported distribution $NAME $VERSION_ID"
|
||||
exit 1;;
|
||||
esac;;
|
||||
openSUSE*)
|
||||
branding="openSUSE"
|
||||
release_pkg="openSUSE-release"
|
||||
base_pattern="patterns-openSUSE-base"
|
||||
case "$VERSION" in
|
||||
13.1\ *)
|
||||
kiwi_boot="13.1"
|
||||
repos="obs://13.1/repo/oss"
|
||||
;;
|
||||
13.2\ *)
|
||||
kiwi_boot="13.2"
|
||||
repos="obs://13.2/repo/oss"
|
||||
;;
|
||||
42.1)
|
||||
kiwi_boot="leap42.1"
|
||||
repos="obs://leap/42.1/repo/oss"
|
||||
;;
|
||||
*\ \(Tumbleweed\))
|
||||
kiwi_boot="leap42.1"
|
||||
repos="obs://openSUSE:Factory/standard"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported distribution $NAME $VERSION_ID"
|
||||
exit 1;;
|
||||
esac;;
|
||||
*)
|
||||
echo "Unsupported distribution $NAME $VERSION"
|
||||
exit 1;;
|
||||
esac
|
||||
|
||||
# Compute the repos
|
||||
repos_xml=
|
||||
for repo in $repos; do
|
||||
repos_xml=" <repository type=\"rpm-md\">\n <source path=\"$repo\"/>\n </repository>\n$repos_xml"
|
||||
done
|
||||
|
||||
mkdir $output
|
||||
cp $datadir/kiwi-config.sh $output/config.sh
|
||||
|
||||
mkdir -p $output/root/etc/sysconfig/network
|
||||
cat >$output/root/etc/sysconfig/network/ifcfg-eth0 << EOF
|
||||
BOOTPROTO='dhcp'
|
||||
MTU=''
|
||||
REMOTE_IPADDR=''
|
||||
STARTMODE='onboot'
|
||||
EOF
|
||||
|
||||
mkdir -p $output/root/etc/systemd/system
|
||||
cp $datadir/p2v.service $output/root/etc/systemd/system
|
||||
|
||||
mkdir -p $output/root/etc/udev/rules.d
|
||||
cat >$output/root/etc/udev/rules.d/70-persistent-net.rules <<EOF
|
||||
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="?*", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="?*", NAME="eth0"
|
||||
EOF
|
||||
|
||||
cp $datadir/issue $output/root/etc/issue
|
||||
|
||||
mkdir -p $output/root/usr/bin
|
||||
cp $datadir/launch-virt-p2v $output/root/usr/bin
|
||||
xzcat $libdir/virt-p2v.xz > $output/root/usr/bin/virt-p2v
|
||||
|
||||
if test "z$ssh_identity" != "z"; then
|
||||
mkdir -p $output/root/var/tmp
|
||||
cp $ssh_identity $output/root/var/tmp/id_rsa
|
||||
chmod 0600 $output/root/var/tmp/id_rsa
|
||||
fi
|
||||
|
||||
# Now generate the final kiwi config, substituting as necessary.
|
||||
@AWK@ \
|
||||
-v "dependencies=$dependencies" \
|
||||
-v "md5sum_virt_p2v=$md5sum_virt_p2v" \
|
||||
-v "branding=$branding" \
|
||||
-v "release_pkg=$release_pkg" \
|
||||
-v "base_pattern=$base_pattern" \
|
||||
-v "kiwi_boot=$kiwi_boot" \
|
||||
-v "repos=$repos_xml" \
|
||||
'{
|
||||
gsub (/__PACKAGE_NAME__/, "@PACKAGE_NAME@");
|
||||
gsub (/__PACKAGE_VERSION__/, "@PACKAGE_VERSION@");
|
||||
gsub (/__PACKAGE_VERSION_FULL__/, "@PACKAGE_VERSION_FULL@");
|
||||
gsub (/<!--__DEPENDENCIES__-->/, dependencies);
|
||||
gsub (/__BRANDING__/, branding);
|
||||
gsub (/__RELEASE_PKG__/, release_pkg);
|
||||
gsub (/__BASE_PATTERN__/, base_pattern);
|
||||
gsub (/__KIWI_BOOT__/, kiwi_boot);
|
||||
gsub (/<!--__REPOS__-->/, repos);
|
||||
print;
|
||||
}' \
|
||||
$datadir/kiwi-config.xml.in > $output/config.xml
|
||||
|
||||
echo "kiwi config folder written to $output"
|
||||
@@ -1,184 +0,0 @@
|
||||
=head1 NAME
|
||||
|
||||
virt-p2v-make-kiwi - Build the virt-p2v kiwi configuration
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
virt-p2v-make-kiwi [--inject-ssh-identity path] [-o kiwi-folder]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<virt-p2v(1)> converts a physical machine to run virtualized on KVM,
|
||||
managed by libvirt, OpenStack, oVirt, Red Hat Enterprise
|
||||
Virtualisation (RHEV), or one of the other targets supported by
|
||||
L<virt-v2v(1)>.
|
||||
|
||||
Kiwi is a tool used mainly by SUSE Linux Enterprise and openSUSE to
|
||||
build live CDs, make appliances and so on. It is driven by a few files
|
||||
including an xml description of the machine.
|
||||
|
||||
virt-p2v-make-kiwi builds a folder containing all the pieces needed for
|
||||
kiwi to build a bootable P2V live CD ISO, USB key, or PXE image. This tool
|
||||
only builds the kiwi configuration, but this manual page describes some of
|
||||
the ways you can use the kiwi configuration.
|
||||
|
||||
=head1 BUILDING THE KIWI CONFIGURATION
|
||||
|
||||
Using virt-p2v-make-kiwi is very simple:
|
||||
|
||||
virt-p2v-make-kiwi
|
||||
|
||||
will build a kiwi configuration based on the current machine’s distribution.
|
||||
|
||||
To control the name of the output folder, use the I<-o> parameter.
|
||||
|
||||
=head1 BUILDING A LIVE CD / ISO
|
||||
|
||||
Once you have the kiwi configuration folder, you can use L<kiwi(1)> to make a
|
||||
live CD:
|
||||
|
||||
sudo kiwi --build p2v.kiwi -d build --type iso
|
||||
|
||||
Before running this, you may have to tweak the C<config.xml> file
|
||||
to change the locale and keyboard mapping to the one you need.
|
||||
|
||||
If running on a SUSE Linux Entreprise Server, add the path to your packages repositories
|
||||
using the C<--ignore-repos> and C<--add-repo> kiwi parameters.
|
||||
|
||||
The generated ISO image will be placed in the C<build> folder.
|
||||
|
||||
=head1 BUILDING A BOOTABLE USB KEY
|
||||
|
||||
Use the L<dd(1)> program to write the ISO created above to a USB key:
|
||||
|
||||
sudo dd if=path/to/p2v.iso of=/dev/sdX
|
||||
|
||||
=head1 BUILDING A PXE BOOT IMAGE
|
||||
|
||||
To create a PXE boot image, run kiwi in such a way:
|
||||
|
||||
sudo kiwi --build $PWD/p2v.kiwi -d build --add-profile netboot --type pxe
|
||||
|
||||
For more details on how to use the generated image, report to the kiwi documentation
|
||||
on PXE images: L<https://doc.opensuse.org/projects/kiwi/doc/#chap.pxe>
|
||||
|
||||
=head1 ADDING AN SSH IDENTITY
|
||||
|
||||
You can inject an SSH identity (private key) file to the kiwi config and
|
||||
hence into the ISO using the I<--inject-ssh-identity> option. Note
|
||||
that you I<cannot> inject a key once the ISO has been built.
|
||||
|
||||
First create a key pair. It must have an empty passphrase:
|
||||
|
||||
ssh-keygen -t rsa -N '' -f id_rsa
|
||||
|
||||
This creates a private key (C<id_rsa>) and a public key
|
||||
(C<id_rsa.pub>) pair. The public key should be appended to the
|
||||
C<authorized_keys> file on the virt-v2v conversion server (usually to
|
||||
C</root/.ssh/authorized_keys>).
|
||||
|
||||
The private key should be added to the kiwi config and then
|
||||
discarded:
|
||||
|
||||
virt-p2v-make-kiwi [...] --inject-ssh-identity id_rsa
|
||||
rm id_rsa
|
||||
|
||||
The ISO can then be built from the kickstart in the usual way (see
|
||||
above), and it will contain the embedded SSH identity
|
||||
(F</var/tmp/id_rsa>).
|
||||
|
||||
When booting virt-p2v, specify the URL of the injected file like this:
|
||||
|
||||
│ User name: [root_____________________________] │
|
||||
│ │
|
||||
│ Password: [ <leave this field blank> ] │
|
||||
│ │
|
||||
│ SSH Identity URL: [file:///var/tmp/id_rsa___________] │
|
||||
|
||||
or if using the kernel command line, add:
|
||||
|
||||
p2v.identity=file:///var/tmp/id_rsa
|
||||
|
||||
For more information, see L<virt-p2v(1)/SSH IDENTITIES>.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<--help>
|
||||
|
||||
Display help.
|
||||
|
||||
=item B<--inject-ssh-identity> id_rsa
|
||||
|
||||
Add an SSH identity (private key) file into the kickstart.
|
||||
See L</ADDING AN SSH IDENTITY> above.
|
||||
|
||||
=item B<-o> OUTPUT
|
||||
|
||||
=item B<--output> OUTPUT
|
||||
|
||||
Write kiwi configuration to the C<OUTPUT> folder. If not specified, the default is
|
||||
F<p2v.kiwi> in the current directory.
|
||||
|
||||
=item B<-V>
|
||||
|
||||
=item B<--version>
|
||||
|
||||
Display version number and exit.
|
||||
|
||||
=back
|
||||
|
||||
=head1 FILES
|
||||
|
||||
=over 4
|
||||
|
||||
=item F<$libdir/virt-p2v/virt-p2v.xz>
|
||||
|
||||
The L<virt-p2v(1)> binary which is copied into the kiwi configuration.
|
||||
|
||||
The location of the binary can be changed by setting the
|
||||
C<VIRT_P2V_DATA_DIR> environment variable.
|
||||
|
||||
=item F<$datadir/virt-p2v/issue>
|
||||
|
||||
=item F<$datadir/virt-p2v/launch-virt-p2v.in>
|
||||
|
||||
=item F<$datadir/virt-p2v/kiwi>
|
||||
|
||||
=item F<$datadir/virt-p2v/p2v.service>
|
||||
|
||||
Various data files that are used to make the kiwi appliance.
|
||||
|
||||
The location of these files can be changed by setting the
|
||||
C<VIRT_P2V_DATA_DIR> environment variable.
|
||||
|
||||
=back
|
||||
|
||||
=head1 ENVIRONMENT VARIABLES
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<VIRT_P2V_DATA_DIR>
|
||||
|
||||
The directory where virt-p2v-make-kiwi looks for data files and
|
||||
the virt-p2v binary (see L</FILES> above). If not set, a compiled-in
|
||||
location is used.
|
||||
|
||||
=back
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<virt-p2v(1)>,
|
||||
L<virt-p2v-make-disk(1)>,
|
||||
L<virt-v2v(1)>,
|
||||
L<kiwi(1)>,
|
||||
L<http://libguestfs.org/>.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Cédric Bosdonnat
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (C) 2016 SUSE Ltd.
|
||||
757
p2v/virt-p2v.pod
757
p2v/virt-p2v.pod
@@ -1,757 +0,0 @@
|
||||
=head1 NAME
|
||||
|
||||
virt-p2v - Convert a physical machine to use KVM
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
virt-p2v
|
||||
|
||||
virt-p2v.iso
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Virt-p2v converts a physical machine to run virtualized on KVM,
|
||||
managed by libvirt, OpenStack, oVirt, Red Hat Virtualisation (RHV), or
|
||||
one of the other targets supported by L<virt-v2v(1)>.
|
||||
|
||||
Normally you don’t run the virt-p2v program directly. Instead you
|
||||
have to boot the physical machine using the bootable CD-ROM, ISO or
|
||||
PXE image. This bootable image contains the virt-p2v binary and runs
|
||||
it automatically. Booting from a CD-ROM/etc is required because the
|
||||
disks which are being converted must be quiescent. It is not safe to
|
||||
try to convert a running physical machine where other programs may be
|
||||
modifying the disk content at the same time.
|
||||
|
||||
This manual page documents running the virt-p2v program. To create
|
||||
the bootable image you should look at L<virt-p2v-make-disk(1)> or
|
||||
L<virt-p2v-make-kickstart(1)>.
|
||||
|
||||
=head1 NETWORK SETUP
|
||||
|
||||
Virt-p2v runs on the physical machine which you want to convert. It
|
||||
has to talk to another server called the "conversion server" which
|
||||
must have L<virt-v2v(1)> installed on it. It always talks to the
|
||||
conversion server over SSH:
|
||||
|
||||
┌──────────────┐ ┌─────────────────┐
|
||||
│ virt-p2v │ │ virt-v2v │
|
||||
│ (physical │ ssh connection │ (conversion │
|
||||
│ server) ╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍▶ server) │
|
||||
└──────────────┘ └─────────────────┘
|
||||
|
||||
The virt-v2v program on the conversion server does the actual
|
||||
conversion (physical to virtual, and virtual to virtual conversions
|
||||
are sufficiently similar that we use the same program to do both).
|
||||
|
||||
The SSH connection is always initiated from the physical server. All
|
||||
data is transferred over the SSH connection. In terms of firewall and
|
||||
network configuration, you only need to ensure that the physical
|
||||
server has access to a port (usually TCP port 22) on the conversion
|
||||
server. Note that the physical machine may reconnect several times
|
||||
during the conversion process.
|
||||
|
||||
The reverse port forwarding feature of ssh (ie. C<ssh -R>) is required
|
||||
by virt-p2v, and it will not work if this is disabled on the
|
||||
conversion server. (C<AllowTcpForwarding> must be C<yes> in the
|
||||
L<sshd_config(5)> file on the conversion server).
|
||||
|
||||
The scp (secure copy) feature of ssh is required by virt-p2v so it can
|
||||
send over small files (this is I<not> the method by which disks are
|
||||
copied).
|
||||
|
||||
The conversion server does not need to be a physical machine. It
|
||||
could be a virtual machine, as long as it has sufficient memory and
|
||||
disk space to do the conversion, and as long as the physical machine
|
||||
can connect directly to its SSH port. (See also
|
||||
L<virt-v2v(1)/Resource requirements>).
|
||||
|
||||
Because all of the data on the physical server’s hard drive(s) has to
|
||||
be copied over the network, the speed of conversion is largely
|
||||
determined by the speed of the network between the two machines.
|
||||
|
||||
=head1 GUI INTERACTIVE CONFIGURATION
|
||||
|
||||
When you start virt-p2v, you'll see a graphical configuration dialog
|
||||
that walks you through connection to the conversion server, asks for
|
||||
the password, which local hard disks you want to convert, and other
|
||||
things like the name of the guest to create and the number of virtual
|
||||
CPUs to give it.
|
||||
|
||||
=head2 SSH CONFIGURATION DIALOG
|
||||
|
||||
When virt-p2v starts up in GUI mode, the first dialog looks like this:
|
||||
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ virt-p2v │
|
||||
│ │
|
||||
│ Conversion server: [____________________________] : [22___] │
|
||||
│ │
|
||||
│ User name: [root__________________________________] │
|
||||
│ │
|
||||
│ Password: [______________________________________] │
|
||||
│ │
|
||||
│ SSH Identity URL: [______________________________________] │
|
||||
│ │
|
||||
|
||||
In the fields above, you must enter the details of the conversion
|
||||
server: the hostname, SSH port number, remote user name, and either
|
||||
the password or SSH identity (private key) URL. The conversion server
|
||||
must have an up to date version of virt-v2v.
|
||||
|
||||
Normally you must log in to the conversion server as root, but if you
|
||||
check the following box:
|
||||
|
||||
│ │
|
||||
│ [ ] Use sudo when running virt-v2v │
|
||||
│ │
|
||||
|
||||
then you can log in as another user, and virt-p2v will use the
|
||||
L<sudo(8)> command to elevate privileges to root. Note that
|
||||
sudo must not require a password.
|
||||
|
||||
It is also possible to run virt-v2v on the conversion server entirely
|
||||
as non-root, but output modes may be limited. Consult the
|
||||
L<virt-v2v(1)> manual page for details.
|
||||
|
||||
At the bottom of the dialog are these buttons:
|
||||
|
||||
│ │
|
||||
│ [ Test connection ] │
|
||||
│ │
|
||||
│ [ Configure network ] [ XTerm ] [ About virt-p2v ] [ Next ] │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
You must press the C<Test connection> button first to test the SSH
|
||||
connection to the conversion server. If that is successful (ie. you
|
||||
have supplied the correct server name, user name, password, etc., and
|
||||
a suitable version of virt-v2v is available remotely) then press the
|
||||
C<Next> button to move to the next dialog.
|
||||
|
||||
You can use the C<Configure network> button if you need to assign a
|
||||
static IP address to the physical machine, or use Wifi, bonding or
|
||||
other network features.
|
||||
|
||||
The C<XTerm> button opens a shell which can be used for diagnostics,
|
||||
manual network configuration, and so on.
|
||||
|
||||
=head2 DISK AND NETWORK CONFIGURATION DIALOG
|
||||
|
||||
The second configuration dialog lets you configure the details of
|
||||
conversion, including what to convert and where to send the guest.
|
||||
|
||||
In the left hand column, starting at the top, the target properties
|
||||
let you select the name of the guest (ie. after conversion) and how
|
||||
many virtual CPUs and how much RAM to give it. The defaults come from
|
||||
the physical machine, and you can usually leave them unchanged:
|
||||
|
||||
┌─────────────────────────────────────── ─ ─ ─ ─
|
||||
│ Target properties:
|
||||
│
|
||||
│ Name: [hostname______________]
|
||||
│
|
||||
│ # vCPUs: [4_____________________]
|
||||
│
|
||||
│ Memory (MB): [16384_________________]
|
||||
│
|
||||
|
||||
The second panel on the left controls the virt-v2v output options. To
|
||||
understand these options it is a really good idea to read the
|
||||
L<virt-v2v(1)> manual page. You can leave the options at the default
|
||||
to create a guest as a disk image plus libvirt XML file located in
|
||||
F</var/tmp> on the conversion host. This is a good idea if you are a
|
||||
first-time virt-p2v user.
|
||||
|
||||
│
|
||||
│ Virt-v2v output options:
|
||||
│
|
||||
│ Output to (-o): [local ▼]
|
||||
│
|
||||
│ Output conn. (-oc): [___________________]
|
||||
│
|
||||
│ Output storage (-os): [/var/tmp___________]
|
||||
│
|
||||
│ Output format (-of): [___________________]
|
||||
│
|
||||
│ Output allocation (-oa): [sparse ▼]
|
||||
│
|
||||
|
||||
All output options and paths are relative to the conversion server
|
||||
(I<not> to the physical server).
|
||||
|
||||
Finally in the left hand column is an information box giving the
|
||||
version of virt-p2v (on the physical server) and virt-v2v (on the
|
||||
conversion server). You should supply this information when reporting
|
||||
bugs.
|
||||
|
||||
In the right hand column are three panels which control what hard
|
||||
disks, removable media devices, and network interfaces, will be
|
||||
created in the output guest. Normally leaving these at the default
|
||||
settings is fine.
|
||||
|
||||
─ ─ ───────────────────────────────────────┐
|
||||
Fixed hard disks │
|
||||
│
|
||||
Convert Device │
|
||||
[✔] sda │
|
||||
1024G HITACHI │
|
||||
s/n 12345 │
|
||||
[✔] sdb │
|
||||
119G HITACHI │
|
||||
s/n 12346 │
|
||||
│
|
||||
|
||||
Normally you would want to convert all hard disks. If you want
|
||||
virt-p2v to completely ignore a local hard disk, uncheck it. The hard
|
||||
disk that contains the operating system must be selected. If a hard
|
||||
disk is part of a RAID array or LVM volume group (VG), then either all
|
||||
hard disks in that array/VG must be selected, or none of them.
|
||||
|
||||
│
|
||||
Removable media │
|
||||
│
|
||||
Convert Device │
|
||||
[✔] sr0 │
|
||||
│
|
||||
|
||||
If the physical machine has CD or DVD drives, then you can use the
|
||||
Removable media panel to create corresponding drives on the guest
|
||||
after conversion. Note that any data CDs/DVDs which are mounted in
|
||||
the drives are I<not> copied over.
|
||||
|
||||
│
|
||||
Network interfaces │
|
||||
│
|
||||
Convert Device Connect to ... |
|
||||
[✔] em1 [default_____________] │
|
||||
[ ] wlp3s0 [default_____________] │
|
||||
│
|
||||
|
||||
In the Network interfaces panel, select the network interfaces that
|
||||
should be created in the guest after conversion. You can also connect
|
||||
these to target hypervisor networks (for further information about
|
||||
this feature, see L<virt-v2v(1)/Networks and bridges>).
|
||||
|
||||
On supported hardware, left-clicking on the device name (eg. C<em1>)
|
||||
causes a light to start flashing on the physical interface, allowing
|
||||
the interface to be identified by the operator.
|
||||
|
||||
When you are ready to begin the conversion, press the
|
||||
C<Start conversion> button:
|
||||
|
||||
│
|
||||
[ Back ] [ Start conversion ] │
|
||||
│
|
||||
─ ─ ───────────────────────────────────────┘
|
||||
|
||||
=head2 CONVERSION RUNNING DIALOG
|
||||
|
||||
When conversion is running you will see this dialog:
|
||||
|
||||
┌────────────────────────────────────────────────────────┐
|
||||
│ virt-p2v │
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────────────────┐ │
|
||||
│ │ ▲│ │
|
||||
│ │ │ │
|
||||
│ │ │ │
|
||||
∼ ∼ ∼ ∼
|
||||
│ │ │ │
|
||||
│ │ │ │
|
||||
│ │ ▼│ │
|
||||
│ └──────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Log files ... to /tmp/virt-p2v-xxx │
|
||||
│ │
|
||||
│ Doing conversion ... │
|
||||
│ │
|
||||
│ [ Cancel conversion ] │
|
||||
│ │
|
||||
└────────────────────────────────────────────────────────┘
|
||||
|
||||
In the main scrolling area you will see messages from the virt-v2v
|
||||
process.
|
||||
|
||||
Below the main area, virt-p2v shows you the location of the directory
|
||||
on the conversion server that contains log files and other debugging
|
||||
information. Below that is the current status and a button for
|
||||
cancelling conversion.
|
||||
|
||||
Once conversion has finished, you should shut down the physical
|
||||
machine. If conversion is successful, you should never reboot it.
|
||||
|
||||
=head1 KERNEL COMMAND LINE CONFIGURATION
|
||||
|
||||
If you don’t want to configure things using the graphical UI, an
|
||||
alternative is to configure through the kernel command line. This is
|
||||
especially convenient if you are converting a lot of physical machines
|
||||
which are booted using PXE.
|
||||
|
||||
Where exactly you set command line arguments depends on your PXE
|
||||
implementation, but for pxelinux you put them in the C<APPEND> field
|
||||
in the F<pxelinux.cfg> file. For example:
|
||||
|
||||
DEFAULT p2v
|
||||
TIMEOUT 20
|
||||
PROMPT 0
|
||||
LABEL p2v
|
||||
KERNEL vmlinuz0
|
||||
APPEND initrd=initrd0.img [....] p2v.server=conv.example.com p2v.password=secret p2v.o=libvirt
|
||||
|
||||
You have to set some or all of the following command line arguments:
|
||||
|
||||
=over 4
|
||||
|
||||
__KERNEL_CONFIG__
|
||||
|
||||
=item B<p2v.pre=COMMAND>
|
||||
|
||||
=item B<p2v.pre="COMMAND ARG ...">
|
||||
|
||||
Select a pre-conversion command to run. Any command or script can be
|
||||
specified here. If the command contains spaces, you must quote the
|
||||
whole command with double quotes. The default is not to run any
|
||||
command.
|
||||
|
||||
=item B<p2v.post=poweroff>
|
||||
|
||||
=item B<p2v.post=reboot>
|
||||
|
||||
=item B<p2v.post=COMMAND>
|
||||
|
||||
=item B<p2v.post="COMMAND ARG ...">
|
||||
|
||||
Select a post-conversion command to run if conversion is successful.
|
||||
This can be any command or script. If the command contains spaces,
|
||||
you must quote the whole command with double quotes.
|
||||
|
||||
I<If> virt-p2v is running as root, I<and> the command line was set
|
||||
from F</proc/cmdline> (not I<--cmdline>), then the default is to run
|
||||
the L<poweroff(8)> command. Otherwise the default is not to run any
|
||||
command.
|
||||
|
||||
=item B<p2v.fail=COMMAND>
|
||||
|
||||
=item B<p2v.fail="COMMAND ARG ...">
|
||||
|
||||
Select a post-conversion command to run if conversion fails. Any
|
||||
command or script can be specified here. If the command contains
|
||||
spaces, you must quote the whole command with double quotes. The
|
||||
default is not to run any command.
|
||||
|
||||
=item B<ip=dhcp>
|
||||
|
||||
Use DHCP for configuring the network interface (this is the default).
|
||||
|
||||
=begin comment
|
||||
|
||||
=item B<ip=ADDR:GATEWAY:NETMASK>
|
||||
|
||||
Set up a static IPv4 network configuration.
|
||||
|
||||
=end comment
|
||||
|
||||
=back
|
||||
|
||||
=head1 SSH IDENTITIES
|
||||
|
||||
As a somewhat more secure alternative to password authentication, you
|
||||
can use an SSH identity (private key) for authentication.
|
||||
|
||||
First create a key pair. It must have an empty passphrase:
|
||||
|
||||
ssh-keygen -t rsa -N '' -f id_rsa
|
||||
|
||||
This creates a private key (C<id_rsa>) and a public key
|
||||
(C<id_rsa.pub>) pair.
|
||||
|
||||
The public key should be appended to the C<authorized_keys> file on
|
||||
the virt-v2v conversion server (usually to
|
||||
C</root/.ssh/authorized_keys>).
|
||||
|
||||
For distributing the private key, there are four scenarios from least
|
||||
secure to most secure:
|
||||
|
||||
=over 4
|
||||
|
||||
=item 1.
|
||||
|
||||
Not using SSH identities at all, ie. password authentication.
|
||||
|
||||
Anyone who can sniff the PXE boot parameters from the network or
|
||||
observe the password some other way can log in to the virt-v2v
|
||||
conversion server.
|
||||
|
||||
=item 2.
|
||||
|
||||
SSH identity embedded in the virt-p2v ISO or disk image. In the GUI, use:
|
||||
|
||||
│ Password: [ <leave this field blank> ] │
|
||||
│ │
|
||||
│ SSH Identity URL: [file:///var/tmp/id_rsa_____________] │
|
||||
|
||||
or on the kernel command line:
|
||||
|
||||
p2v.identity=file:///var/tmp/id_rsa
|
||||
|
||||
The SSH private key can still be sniffed from the network if using
|
||||
standard PXE.
|
||||
|
||||
=item 3.
|
||||
|
||||
SSH identity downloaded from a website. In the GUI, use:
|
||||
|
||||
│ Password: [ <leave this field blank> ] │
|
||||
│ │
|
||||
│ SSH Identity URL: [https://internal.example.com/id_rsa] │
|
||||
|
||||
or on the kernel command line:
|
||||
|
||||
p2v.identity=https://internal.example.com/id_rsa
|
||||
|
||||
Anyone could still download the private key and use it to log in to
|
||||
the virt-v2v conversion server, but you could provide some extra
|
||||
security by configuring the web server to only allow connections from
|
||||
P2V machines.
|
||||
|
||||
Note that L<ssh-keygen(1)> creates the C<id_rsa> (private key) file
|
||||
with mode 0600. If you simply copy the file to a webserver, the
|
||||
webserver will not serve it. It will reply with "403 Forbidden"
|
||||
errors. You will need to change the mode of the file to make it
|
||||
publicly readable, for example by using:
|
||||
|
||||
chmod 0644 id_rsa
|
||||
|
||||
=item 4.
|
||||
|
||||
SSH identity embedded in the virt-p2v ISO or disk image (like 2.),
|
||||
I<and> use of secure PXE, PXE over separate physical network, or
|
||||
sneakernet to distribute virt-p2v to the physical machine.
|
||||
|
||||
=back
|
||||
|
||||
Both L<virt-p2v-make-disk(1)> and L<virt-p2v-make-kickstart(1)> have
|
||||
the same option I<--inject-ssh-identity> for injecting the private key
|
||||
into the virt-p2v disk image / ISO. See also the following manual
|
||||
sections:
|
||||
|
||||
L<virt-p2v-make-disk(1)/ADDING AN SSH IDENTITY>
|
||||
|
||||
L<virt-p2v-make-kickstart(1)/ADDING AN SSH IDENTITY>
|
||||
|
||||
=head1 COMMON PROBLEMS
|
||||
|
||||
=head2 Timeouts
|
||||
|
||||
As described below (see L</HOW VIRT-P2V WORKS>) virt-p2v makes several
|
||||
long-lived ssh connections to the conversion server. If these
|
||||
connections time out then virt-p2v will fail.
|
||||
|
||||
To test if a timeout might be causing problems, open an XTerm on the
|
||||
virt-p2v machine, C<ssh root@I<conversion-server>>, and leave it for
|
||||
at least an hour. If the session disconnects without you doing
|
||||
anything, then there is a timeout which you should turn off.
|
||||
|
||||
Timeouts happen because:
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<TIMEOUT> or C<TMOUT> environment variable
|
||||
|
||||
Check if one of these environment variables is set in the root shell
|
||||
on the conversion server.
|
||||
|
||||
=item sshd C<ClientAlive*> setting
|
||||
|
||||
Check for C<ClientAlive*> settings in C</etc/ssh/sshd_config> on the
|
||||
conversion server.
|
||||
|
||||
=item Firewall or NAT settings
|
||||
|
||||
Check if there is a firewall or NAT box between virt-p2v and the
|
||||
conversion server, and if this firewall drops idle connections after a
|
||||
too-short time.
|
||||
|
||||
virt-p2v E<ge> 1.36 attempts to work around firewall timeouts by
|
||||
sending ssh keepalive messages every 5 minutes.
|
||||
|
||||
=back
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<--help>
|
||||
|
||||
Display help.
|
||||
|
||||
=item B<--cmdline=CMDLINE>
|
||||
|
||||
This is used for debugging. Instead of parsing the kernel command line
|
||||
from F</proc/cmdline>, parse the string parameter C<CMDLINE>.
|
||||
|
||||
=item B<--colors>
|
||||
|
||||
=item B<--colours>
|
||||
|
||||
Use ANSI colour sequences to colourize messages. This is the default
|
||||
when the output is a tty. If the output of the program is redirected
|
||||
to a file, ANSI colour sequences are disabled unless you use this
|
||||
option.
|
||||
|
||||
=item B<--iso>
|
||||
|
||||
This flag is passed to virt-p2v when it is launched inside the
|
||||
virt-p2v ISO environment, ie. when it is running on a real physical
|
||||
machine (and thus not when testing). It enables various dangerous
|
||||
features such as the Shutdown popup button.
|
||||
|
||||
=item B<--nbd=server[,server...]>
|
||||
|
||||
Select which NBD server is used. By default the following servers are
|
||||
checked and the first one found is used:
|
||||
I<--nbd=qemu-nbd,qemu-nbd-no-sa,nbdkit,nbdkit-no-sa>
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<qemu-nbd>
|
||||
|
||||
Use qemu-nbd.
|
||||
|
||||
=item B<qemu-nbd-no-sa>
|
||||
|
||||
Use qemu-nbd, but disable socket activation.
|
||||
|
||||
=item B<nbdkit>
|
||||
|
||||
Use nbdkit with the file plugin (see: L<nbdkit-file-plugin(1)>).
|
||||
|
||||
=item B<nbdkit-no-sa>
|
||||
|
||||
Use nbdkit, but disable socket activation
|
||||
|
||||
=back
|
||||
|
||||
The C<*-no-sa> variants allow virt-p2v to fall back to older versions
|
||||
of qemu-nbd and nbdkit which did not support
|
||||
L<socket activation|http://0pointer.de/blog/projects/socket-activation.html>.
|
||||
|
||||
=item B<--test-disk=/PATH/TO/DISK.IMG>
|
||||
|
||||
For testing or debugging purposes, replace F</dev/sda> with a local
|
||||
file. You must use an absolute path.
|
||||
|
||||
=item B<-v>
|
||||
|
||||
=item B<--verbose>
|
||||
|
||||
In libguestfs E<ge> 1.33.41, debugging is always enabled on the
|
||||
conversion server, and this option does nothing.
|
||||
|
||||
=item B<-V>
|
||||
|
||||
=item B<--version>
|
||||
|
||||
Display version number and exit.
|
||||
|
||||
=back
|
||||
|
||||
=head1 HOW VIRT-P2V WORKS
|
||||
|
||||
B<Note this section is not normative.> We may change how virt-p2v
|
||||
works at any time in the future.
|
||||
|
||||
As described above, virt-p2v runs on a physical machine, interrogates
|
||||
the user or the kernel command line for configuration, and then
|
||||
establishes one or more ssh connections to the virt-v2v conversion
|
||||
server. The ssh connections are interactive shell sessions to the
|
||||
remote host, but the commands sent are generated entirely by virt-p2v
|
||||
itself, not by the user. For data transfer, virt-p2v will use the
|
||||
reverse port forward feature of ssh (ie. C<ssh -R>).
|
||||
|
||||
It will first make one or more test connections, which are used to
|
||||
query the remote version of virt-v2v and its features. The test
|
||||
connections are closed before conversion begins.
|
||||
|
||||
┌──────────────┐ ┌─────────────────┐
|
||||
│ virt-p2v │ │ virt-v2v │
|
||||
│ (physical │ control connection │ (conversion │
|
||||
│ server) ╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍▶ server) │
|
||||
└──────────────┘ └─────────────────┘
|
||||
|
||||
Once virt-p2v is ready to start conversion, it will open a single ssh
|
||||
control connection. It first sends a mkdir command to create a
|
||||
temporary directory on the conversion server. The directory name is
|
||||
randomly chosen and is displayed in the GUI. It has the form:
|
||||
|
||||
/tmp/virt-p2v-YYYYMMDD-XXXXXXXX
|
||||
|
||||
where C<YYYYMMDD> is the current date, and the ‘X’s are random
|
||||
characters.
|
||||
|
||||
Into this directory are written various files which include:
|
||||
|
||||
=over 4
|
||||
|
||||
=item F<dmesg>
|
||||
|
||||
=item F<lscpu>
|
||||
|
||||
=item F<lspci>
|
||||
|
||||
=item F<lsscsi>
|
||||
|
||||
=item F<lsusb>
|
||||
|
||||
I<(before conversion)>
|
||||
|
||||
The output of the corresponding commands (ie L<dmesg(1)>, L<lscpu(1)>
|
||||
etc) on the physical machine.
|
||||
|
||||
The dmesg output is useful for detecting problems such as missing
|
||||
device drivers or firmware on the virt-p2v ISO. The others are useful
|
||||
for debugging novel hardware configurations.
|
||||
|
||||
=item F<environment>
|
||||
|
||||
I<(before conversion)>
|
||||
|
||||
The content of the environment where L<virt-v2v(1)> will run.
|
||||
|
||||
=item F<name>
|
||||
|
||||
I<(before conversion)>
|
||||
|
||||
The name (usually the hostname) of the physical machine.
|
||||
|
||||
=item F<physical.xml>
|
||||
|
||||
I<(before conversion)>
|
||||
|
||||
Libvirt XML describing the physical machine. It is used to pass data
|
||||
about the physical source host to L<virt-v2v(1)> via the I<-i libvirtxml>
|
||||
option.
|
||||
|
||||
Note this is not "real" libvirt XML (and must B<never> be loaded into
|
||||
libvirt, which would reject it anyhow). Also it is not the same as
|
||||
the libvirt XML which virt-v2v generates in certain output modes.
|
||||
|
||||
=item F<p2v-version>
|
||||
|
||||
=item F<v2v-version>
|
||||
|
||||
I<(before conversion)>
|
||||
|
||||
The versions of virt-p2v and virt-v2v respectively.
|
||||
|
||||
=item F<status>
|
||||
|
||||
I<(after conversion)>
|
||||
|
||||
The final status of the conversion. C<0> if the conversion was
|
||||
successful. Non-zero if the conversion failed.
|
||||
|
||||
=item F<time>
|
||||
|
||||
I<(before conversion)>
|
||||
|
||||
The start date/time of conversion.
|
||||
|
||||
=item F<virt-v2v-conversion-log.txt>
|
||||
|
||||
I<(during/after conversion)>
|
||||
|
||||
The conversion log. This is just the output of the virt-v2v command
|
||||
on the conversion server. If conversion fails, you should examine
|
||||
this log file, and you may be asked to supply the B<complete>,
|
||||
B<unedited> log file in any bug reports or support tickets.
|
||||
|
||||
=item F<virt-v2v-wrapper.sh>
|
||||
|
||||
I<(before conversion)>
|
||||
|
||||
This is the wrapper script which is used when running virt-v2v. For
|
||||
interest only, do not attempt to run this script yourself.
|
||||
|
||||
=back
|
||||
|
||||
Before conversion actually begins, virt-p2v then makes one or more
|
||||
further ssh connections to the server for data transfer.
|
||||
|
||||
The transfer protocol used currently is NBD (Network Block Device),
|
||||
which is proxied over ssh. The NBD server is L<qemu-nbd(1)> by
|
||||
default but others can be selected using the I<--nbd> command line
|
||||
option.
|
||||
|
||||
There is one ssh connection per physical hard disk on the source
|
||||
machine (the common case — a single hard disk — is shown below):
|
||||
|
||||
┌──────────────┐ ┌─────────────────┐
|
||||
│ virt-p2v │ │ virt-v2v │
|
||||
│ (physical │ control connection │ (conversion │
|
||||
│ server) ╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍▶ server) │
|
||||
│ │ │ │
|
||||
│ │ data connection │ │
|
||||
│ ╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍▶ │
|
||||
│qemu-nbd ← ─┘ │ │└─ ← NBD │
|
||||
│/dev/sda │ │ requests │
|
||||
∼ ∼ ∼ ∼
|
||||
└──────────────┘ └─────────────────┘
|
||||
|
||||
Although the ssh data connection is originated from the physical
|
||||
server and terminates on the conversion server, in fact NBD requests
|
||||
flow in the opposite direction. This is because the reverse port
|
||||
forward feature of ssh (C<ssh -R>) is used to open a port on the
|
||||
loopback interface of the conversion server which is proxied back by
|
||||
ssh to the NBD server running on the physical machine. The effect is
|
||||
that virt-v2v via libguestfs can open nbd connections which directly
|
||||
read the hard disk(s) of the physical server.
|
||||
|
||||
Two layers of protection are used to ensure that there are no writes
|
||||
to the hard disks: Firstly, the qemu-nbd I<-r> (readonly) option is
|
||||
used. Secondly libguestfs creates an overlay on top of the NBD
|
||||
connection which stores writes in a temporary file on the conversion
|
||||
file.
|
||||
|
||||
The long S<C<virt-v2v -i libvirtxml physical.xml ...>> command is
|
||||
wrapped inside a wrapper script and uploaded to the conversion server.
|
||||
The final step is to run this wrapper script, in turn running the
|
||||
virt-v2v command. The virt-v2v command references the F<physical.xml>
|
||||
file (see above), which in turn references the NBD listening port(s)
|
||||
of the data connection(s).
|
||||
|
||||
Output from the virt-v2v command (messages, debugging etc) is saved
|
||||
both in the log file on the conversion server. Only informational
|
||||
messages are sent back over the control connection to be displayed in
|
||||
the graphical UI.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<virt-p2v-make-disk(1)>,
|
||||
L<virt-p2v-make-kickstart(1)>,
|
||||
L<virt-p2v-make-kiwi(1)>,
|
||||
L<virt-v2v(1)>,
|
||||
L<qemu-nbd(1)>,
|
||||
L<nbdkit(1)>, L<nbdkit-file-plugin(1)>,
|
||||
L<ssh(1)>,
|
||||
L<sshd(8)>,
|
||||
L<sshd_config(5)>,
|
||||
L<http://libguestfs.org/>.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Matthew Booth
|
||||
|
||||
John Eckersberg
|
||||
|
||||
Richard W.M. Jones L<http://people.redhat.com/~rjones/>
|
||||
|
||||
Mike Latimer
|
||||
|
||||
Pino Toscano
|
||||
|
||||
Tingting Zheng
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (C) 2009-2019 Red Hat Inc.
|
||||
@@ -1,95 +0,0 @@
|
||||
/* libguestfs
|
||||
* Copyright (C) 2011-2019 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "p2v.h"
|
||||
|
||||
/**
|
||||
* Read the whole file into a memory buffer and return it. The file
|
||||
* should be a regular, local, trusted file.
|
||||
*/
|
||||
int
|
||||
read_whole_file (const char *filename, char **data_r, size_t *size_r)
|
||||
{
|
||||
int fd;
|
||||
char *data;
|
||||
off_t size;
|
||||
off_t n;
|
||||
ssize_t r;
|
||||
struct stat statbuf;
|
||||
|
||||
fd = open (filename, O_RDONLY|O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
fprintf (stderr, "open: %s: %m\n", filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fstat (fd, &statbuf) == -1) {
|
||||
fprintf (stderr, "stat: %s: %m\n", filename);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size = statbuf.st_size;
|
||||
data = malloc (size + 1);
|
||||
if (data == NULL) {
|
||||
perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = 0;
|
||||
while (n < size) {
|
||||
r = read (fd, &data[n], size - n);
|
||||
if (r == -1) {
|
||||
fprintf (stderr, "read: %s: %m\n", filename);
|
||||
free (data);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
if (r == 0) {
|
||||
fprintf (stderr, "read: %s: unexpected end of file\n", filename);
|
||||
free (data);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
n += r;
|
||||
}
|
||||
|
||||
if (close (fd) == -1) {
|
||||
fprintf (stderr, "close: %s: %m\n", filename);
|
||||
free (data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* For convenience of callers, \0-terminate the data. */
|
||||
data[size] = '\0';
|
||||
|
||||
*data_r = data;
|
||||
if (size_r != NULL)
|
||||
*size_r = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -71,9 +71,6 @@ MANPAGES = \
|
||||
virt-log.1 \
|
||||
virt-ls.1 \
|
||||
virt-make-fs.1 \
|
||||
virt-p2v.1 \
|
||||
virt-p2v-make-disk.1 \
|
||||
virt-p2v-make-kickstart.1 \
|
||||
virt-rescue.1 \
|
||||
virt-resize.1 \
|
||||
virt-sparsify.1 \
|
||||
|
||||
@@ -53,11 +53,6 @@
|
||||
../lua/examples/guestfs-lua.pod
|
||||
../make-fs/virt-make-fs.pod
|
||||
../ocaml/examples/guestfs-ocaml.pod
|
||||
../p2v/virt-p2v-kernel-config.pod
|
||||
../p2v/virt-p2v-make-disk.pod
|
||||
../p2v/virt-p2v-make-kickstart.pod
|
||||
../p2v/virt-p2v-make-kiwi.pod
|
||||
../p2v/virt-p2v.pod
|
||||
../perl/examples/guestfs-perl.pod
|
||||
../python/examples/guestfs-python.pod
|
||||
../rescue/virt-rescue.pod
|
||||
|
||||
Reference in New Issue
Block a user