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:
Pino Toscano
2019-07-10 18:29:45 +02:00
parent 730642676b
commit 2c02adb8ba
53 changed files with 0 additions and 12795 deletions

View File

@@ -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

View File

@@ -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 .............. "])

View File

@@ -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;

View File

@@ -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
View File

@@ -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

View File

@@ -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 $@

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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 machines 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";
}

View File

@@ -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 */

View File

@@ -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

2295
p2v/gui.c

File diff suppressed because it is too large Load Diff

View File

@@ -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
}

View File

@@ -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
***

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -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
View File

@@ -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
View File

@@ -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 */

View File

@@ -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

View File

@@ -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

View File

@@ -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
View File

@@ -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 */

1203
p2v/ssh.c

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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));
}

View File

@@ -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 its 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 $?

View File

@@ -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. dont
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.

View File

@@ -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"

View File

@@ -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 qemus 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.

View File

@@ -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"

View File

@@ -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 machines 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.

View File

@@ -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 dont 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 servers 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 dont 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 Xs 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.

View File

@@ -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;
}

View File

@@ -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 \

View File

@@ -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