initial build-vm feature
Yes, mkimage-profiles is now able to build VM disk images. So far the support is pretty basic: - a single hard drive image with a single partition/FS - only stock root password is configurable - LILO is hardwired as a bootloader The resulting images tend to boot under qemu/kvm though. Please see doc/vm.txt for the warning regarding additional privileges and setup required. This was started back in February but I still hoped to avoid sudo/privileged helper (and libguestfs is almost as undistributable as can be)... Thanks: - http://blog.quinthar.com/2008/07/building-1gb-bootable-qemu-image-using.html - Alexey Morarash who reworked that as https://github.com/tuxofil/linsygen - led@, legion@, vitty@, aen@ for providing advice and inspiration
This commit is contained in:
parent
6ab9a3550b
commit
75f7c62bd1
2
README
2
README
@ -32,7 +32,7 @@ Most docs are in Russian, welcome to learn it or ask for English.
|
||||
- сборка образа
|
||||
|
||||
Объекты:
|
||||
- дистрибутивы и виртуальные окружения:
|
||||
- дистрибутивы и виртуальные среды/машины:
|
||||
+ описываются в conf.d/*.mk или соответственно lib/{distro,ve}.mk
|
||||
+ могут основываться на предшественниках, расширяя их
|
||||
+ дистрибутивы также:
|
||||
|
130
bin/tar2vm
Executable file
130
bin/tar2vm
Executable file
@ -0,0 +1,130 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
. shell-error
|
||||
|
||||
if [ $# -lt 2 ]; then
|
||||
fatal "error: tar2vm needs at least two arguments"
|
||||
fi
|
||||
|
||||
# this needs env_keep sudo setup to actually work
|
||||
if [ -n "$GLOBAL_BUILDDIR" ]; then
|
||||
WORKDIR="$GLOBAL_BUILDDIR/vmroot"
|
||||
else
|
||||
WORKDIR="$(mktemp --tmpdir -d vmroot-XXXXX)"
|
||||
fi
|
||||
|
||||
[ -n "$WORKDIR" ] || fatal "couldn't come up with suitable WORKDIR"
|
||||
|
||||
[ -n "$GLOBAL_DEBUG" ] || message "WORKDIR: $WORKDIR"
|
||||
|
||||
# a tarball containing chroot with a kernel
|
||||
TAR="$1"
|
||||
[ -s "$TAR" ] || fatal "source tarball doesn't really exist"
|
||||
|
||||
# a path to the image to be generated
|
||||
IMG="$2"
|
||||
[ -d "$(dirname "$IMG")" ] || fatal "target directory doesn't exist"
|
||||
|
||||
# image size in bytes (256M is a fallback)
|
||||
TARSIZE="$(stat -Lc %s "$TAR")"
|
||||
DEFSIZE="$(expr 3 '*' "$TARSIZE" '/' 2)"
|
||||
DISKSIZE="${3:-${DEFSIZE:-268435456}}"
|
||||
# ...and in megabytes
|
||||
DISKSIZEM="$(expr "$DISKSIZE" / 1048576)"
|
||||
|
||||
# tested to work: ext[234], jfs
|
||||
ROOTFSTYPE="${4:-ext4}"
|
||||
|
||||
# single root partition hardwired so far,
|
||||
# add another image for swap if needed
|
||||
ROOTDEV="/dev/sda1"
|
||||
|
||||
# last preparations...
|
||||
for i in losetup parted kpartx mkfs."$ROOTFSTYPE"; do
|
||||
if ! type -t "$i" >&/dev/null; then
|
||||
fatal "$i required but not found"
|
||||
fi
|
||||
done
|
||||
|
||||
LOOPDEV="$(losetup --find)"
|
||||
ROOTFS="$WORKDIR/chroot"
|
||||
|
||||
exit_handler()
|
||||
{
|
||||
rc=$?
|
||||
if [ -n "$ROOTFS" ]; then
|
||||
umount "$ROOTFS"{/dev,/proc,/sys,}
|
||||
if [ -n "$LOOPDEV" ]; then
|
||||
kpartx -d "$LOOPDEV"
|
||||
losetup --detach "$LOOPDEV"
|
||||
fi
|
||||
rm -r -- "$ROOTFS"
|
||||
rmdir -- "$WORKDIR"
|
||||
fi
|
||||
exit $rc
|
||||
}
|
||||
|
||||
trap exit_handler EXIT
|
||||
|
||||
# prepare disk image and a filesystem inside it
|
||||
rm -f -- "$IMG"
|
||||
dd if=/dev/zero of="$IMG" bs=1 count=1 seek="$DISKSIZE" conv=notrunc
|
||||
losetup "$LOOPDEV" "$IMG"
|
||||
|
||||
parted --script "$LOOPDEV" mklabel msdos
|
||||
parted --script "$LOOPDEV" mkpart primary ext2 1 "$DISKSIZEM"
|
||||
|
||||
kpartx -a "$LOOPDEV"
|
||||
LOOPDEV1="/dev/mapper/$(basename "$LOOPDEV")p1"
|
||||
|
||||
mkfs."$ROOTFSTYPE" "$LOOPDEV1"
|
||||
|
||||
# mount and populate it
|
||||
mkdir -pm755 "$ROOTFS"
|
||||
mount "$LOOPDEV1" "$ROOTFS"
|
||||
tar -C "$ROOTFS" --numeric-owner -xf "$TAR"
|
||||
for i in /dev /proc /sys; do mount --bind "$i" "$ROOTFS$i"; done
|
||||
|
||||
# NB: different storage modules might be needed for non-kvm
|
||||
echo "$LOOPDEV1 / $ROOTFSTYPE defaults 1 1" >> "$ROOTFS/etc/fstab"
|
||||
echo "MODULES_PRELOAD=sd_mod ata_piix $ROOTFSTYPE" >> "$ROOTFS/etc/initrd.mk"
|
||||
|
||||
KERNEL="$(readlink $ROOTFS/boot/vmlinuz | sed 's,vmlinuz-,,')"
|
||||
chroot "$ROOTFS" make-initrd -k "$KERNEL"
|
||||
|
||||
sed -i "s,$LOOPDEV1,$ROOTDEV," "$ROOTFS/etc/fstab"
|
||||
|
||||
# configure and install bootloader
|
||||
REGEXP='^([0-9]+) heads, ([0-9]+) sectors/track, ([0-9]+) cylinders.*$'
|
||||
set -- $(fdisk -l "$LOOPDEV" | grep -E "$REGEXP" | sed -r "s@$REGEXP@\1 \2 \3@")
|
||||
|
||||
LILO_COMMON="lba32
|
||||
delay=1
|
||||
vga=0
|
||||
image=/boot/vmlinuz
|
||||
initrd=/boot/initrd.img
|
||||
append=\"root=$ROOTDEV rootdelay=3\"
|
||||
label=linux"
|
||||
|
||||
cat > "$ROOTFS"/etc/lilo-loop.conf << EOF
|
||||
boot=$LOOPDEV
|
||||
disk=$LOOPDEV
|
||||
bios=0x80
|
||||
heads=$1
|
||||
sectors=$2
|
||||
cylinders=$3
|
||||
partition=$LOOPDEV1
|
||||
start=63
|
||||
$LILO_COMMON
|
||||
EOF
|
||||
|
||||
chroot "$ROOTFS" lilo -C /etc/lilo-loop.conf
|
||||
|
||||
cat > "$ROOTFS"/etc/lilo.conf << EOF
|
||||
boot=${ROOTDEV%[0-9]*}
|
||||
$LILO_COMMON
|
||||
EOF
|
||||
|
||||
if [ -n "$SUDO_USER" ]; then
|
||||
chown "$SUDO_USER" "$IMG" "$ROOTFS" "$WORKDIR"
|
||||
fi
|
@ -76,6 +76,11 @@
|
||||
+ NB: в силу специфики обработки передаётся только явно
|
||||
+ см. ../Makefile, ../report.mk, ../lib/report.mk
|
||||
|
||||
- ROOTPW
|
||||
+ устанавливает пароль root по умолчанию для образов виртуальных машин
|
||||
+ значение: пусто (по умолчанию root) либо строка
|
||||
+ см. ../features.in/build-vm/image-scripts.d/00root
|
||||
|
||||
- SAVE_PROFILE
|
||||
+ сохраняет архив сгенерированного профиля в .disk/
|
||||
+ значение: пусто (по умолчанию) либо любая строка
|
||||
|
20
doc/vm.txt
Normal file
20
doc/vm.txt
Normal file
@ -0,0 +1,20 @@
|
||||
сборка образов виртуальных машин
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
ВНИМАНИЕ: заключительная операция создания образа жёсткого диска
|
||||
из архива с содержимым корневой файловой системы требует доступа
|
||||
к sudo и разрешения на выполнение скрипта bin/tar2vm в корневом
|
||||
каталоге метапрофиля при установке mkimage-profiles из пакета.
|
||||
|
||||
Соответствующий фрагмент конфигурации sudo(8) может выглядеть как:
|
||||
|
||||
mike ALL=NOPASSWD: /usr/share/mkimage-profiles/bin/tar2vm
|
||||
|
||||
При работе с git следует иметь в виду, что предоставлять недоверенному
|
||||
пользователю право выполнять с повышенными привилегиями доступный ему
|
||||
по записи скрипт равнозначно предоставлению полных привилегий root.
|
||||
|
||||
Также потребуется пакет multipath-tools (/sbin/kpartx).
|
||||
|
||||
Пример сборки и запуска VM:
|
||||
|
||||
$ make ROOTPW=reallysecret1 vm/bare.img && kvm -hda ~/out/bare.img
|
@ -23,7 +23,6 @@ all: $(GLOBAL_DEBUG) prep copy-subdirs copy-tree run-scripts pack-image \
|
||||
postprocess $(GLOBAL_CLEAN_WORKDIR)
|
||||
|
||||
prep: $(GLOBAL_DEBUG) dot-disk $(WHATEVER) imagedir
|
||||
#prep: $(GLOBAL_DEBUG) dot-disk metadata imagedir
|
||||
|
||||
dot-disk:
|
||||
@mkdir -p files/.disk
|
||||
|
3
features.in/build-vm/README
Normal file
3
features.in/build-vm/README
Normal file
@ -0,0 +1,3 @@
|
||||
Эта фича конфигурирует создание образа виртуальной машины (VM).
|
||||
Дополняет финальную стадию сборки (lib/, image-scripts.d/).
|
||||
Требует для работы sudo(8) -- см. тж. ../../doc/vm.txt .
|
3
features.in/build-vm/config.mk
Normal file
3
features.in/build-vm/config.mk
Normal file
@ -0,0 +1,3 @@
|
||||
# hooked from ../../lib/sugar.mk
|
||||
use/build-vm:
|
||||
@$(call add_feature)
|
7
features.in/build-vm/image-scripts.d/00root
Executable file
7
features.in/build-vm/image-scripts.d/00root
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
ROOTPW="${GLOBAL_ROOTPW:-root}"
|
||||
|
||||
if type -t chpasswd >&/dev/null; then
|
||||
echo "root:$ROOTPW" | chpasswd
|
||||
fi
|
9
features.in/build-vm/image-scripts.d/03services
Executable file
9
features.in/build-vm/image-scripts.d/03services
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
# VMs might have no means to communicate with the outer
|
||||
# world except for networking
|
||||
|
||||
[ -x /sbin/chkconfig ] || exit 0
|
||||
|
||||
for i in network random syslogd; do chkconfig $i on; done
|
||||
for i in fbsetfont netfs rawdevices; do chkconfig $i off; done
|
||||
:
|
4
features.in/build-vm/image-scripts.d/04inittab
Executable file
4
features.in/build-vm/image-scripts.d/04inittab
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh -e
|
||||
# we don't need no extra gettys in VMs
|
||||
[ -s /etc/inittab ] || exit 0
|
||||
sed -i 's,^[3-9]\+:[0-9]\+:respawn:/sbin/mingetty.*,#&,' /etc/inittab
|
16
features.in/build-vm/image-scripts.d/06syslog
Executable file
16
features.in/build-vm/image-scripts.d/06syslog
Executable file
@ -0,0 +1,16 @@
|
||||
#!/bin/sh -e
|
||||
# tweak syslog configuration to:
|
||||
# - avoid logging to a nonexistent tty;
|
||||
# - avoid hard sync logging (one is better off doing
|
||||
# remote syslog if you do care for reliable data anyways)
|
||||
# credits: vvk@, thresh@ (2010)
|
||||
|
||||
CONFIG=/etc/syslog.conf
|
||||
|
||||
[ ! -f "$CONFIG" ] || \
|
||||
sed -i \
|
||||
-e 's,/dev/tty12,/var/log/syslog/console,' \
|
||||
-e 's,^.*/var/log/syslog/console$,#&,' \
|
||||
-e 's,-/var/log/,/var/log/,g' \
|
||||
-e 's,/var/log/,-/var/log/,g' \
|
||||
"$CONFIG"
|
13
features.in/build-vm/image-scripts.d/07kernel
Executable file
13
features.in/build-vm/image-scripts.d/07kernel
Executable file
@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
# predictable file locations make bootloader configuration simple;
|
||||
# this script relates to .../features.in/stage2/stage1/scripts.d/80-make-initfs
|
||||
|
||||
kver="$(rpm -qa 'kernel-image*' \
|
||||
--qf '%{installtime} %{version}-%{name}-%{release}\n' \
|
||||
| sort -n \
|
||||
| tail -n 1 \
|
||||
| cut -f 2 -d ' ' \
|
||||
| sed 's/kernel-image-//')"
|
||||
|
||||
ln -s vmlinuz-$kver /boot/vmlinuz
|
||||
ln -s initrd-$kver.img /boot/initrd.img
|
33
features.in/build-vm/lib/90-build-vm.mk
Normal file
33
features.in/build-vm/lib/90-build-vm.mk
Normal file
@ -0,0 +1,33 @@
|
||||
# step 4: build the virtual machine image
|
||||
|
||||
IMAGE_PACKAGES = $(SYSTEM_PACKAGES) \
|
||||
$(COMMON_PACKAGES) \
|
||||
$(BASE_PACKAGES) \
|
||||
$(THE_PACKAGES) \
|
||||
$(call list,$(BASE_LISTS) $(THE_LISTS)) \
|
||||
$(call kpackages,$(THE_KMODULES) $(BASE_KMODULES),$(KFLAVOURS))
|
||||
|
||||
# intermediate chroot archive
|
||||
VM_TARBALL := $(IMAGE_OUTDIR)/$(IMAGE_NAME).tar
|
||||
|
||||
check-sudo:
|
||||
@if ! type -t sudo >&/dev/null; then \
|
||||
echo "** error: sudo not available, see doc/vm.txt" >&2; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
convert-image: check-sudo
|
||||
@if ! sudo $(TOPDIR)/bin/tar2vm \
|
||||
"$(VM_TARBALL)" "$(IMAGE_OUTPATH)" $$VM_SIZE; then \
|
||||
echo "** error: sudo tar2vm failed, see also doc/vm.txt" >&2; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
run-image-scripts: GLOBAL_ROOTPW := $(ROOTPW)
|
||||
|
||||
pack-image: MKI_PACK_RESULTS := tar:$(VM_TARBALL)
|
||||
|
||||
all: $(GLOBAL_DEBUG) build-image copy-tree run-image-scripts pack-image \
|
||||
convert-image postprocess $(GLOBAL_CLEAN_WORKDIR)
|
||||
|
||||
prep: imagedir
|
@ -1,3 +1,4 @@
|
||||
# distributions
|
||||
DISTRO_EXTS := .iso
|
||||
|
||||
use/pack:
|
||||
@ -12,6 +13,7 @@ else
|
||||
@$(call set,IMAGE_PACKTYPE,isodata)
|
||||
endif
|
||||
|
||||
# virtual environments
|
||||
VE_ARCHIVES := tar cpio
|
||||
VE_COMPRESSORS := gz xz# there's no sense in bzip2 by now
|
||||
VE_ZIPS := $(call addsuffices, \
|
||||
@ -34,3 +36,8 @@ $(foreach c,$(VE_ARCHIVES), \
|
||||
$(eval $(call PACK_containers,$(c))) \
|
||||
$(foreach z,$(VE_COMPRESSORS), \
|
||||
$(eval $(call PACK_compressors,$(c),$(z)))))
|
||||
|
||||
# virtual machines
|
||||
VM_EXTS := .img
|
||||
|
||||
use/pack/img: use/pack; @:
|
||||
|
16
lib/help.mk
16
lib/help.mk
@ -6,7 +6,7 @@ define help_body
|
||||
endef
|
||||
else
|
||||
define help_body
|
||||
@echo '** available $(1) targets:'; \
|
||||
echo '** available $(1) targets:'; \
|
||||
columnize $(2)
|
||||
endef
|
||||
endif
|
||||
@ -14,11 +14,15 @@ endif
|
||||
help = $(and $(2),$(help_body))
|
||||
|
||||
help/distro:
|
||||
$(call help,distribution,$(sort $(DISTROS:distro/%=%)))
|
||||
@$(call help,distribution,$(sort $(DISTROS:distro/%=%)))
|
||||
|
||||
help/ve:
|
||||
@echo '** available virtual environment targets:'; \
|
||||
columnize $(sort $(VES))
|
||||
@[ -n "$(SPACE)" ] && echo; \
|
||||
$(call help,virtual environment,$(sort $(VES)))
|
||||
|
||||
help: | help/distro help/space help/ve; @:
|
||||
help/space:; @echo
|
||||
help/vm:
|
||||
@[ -n "$(SPACE)" ] && echo; \
|
||||
$(call help,virtual machine,$(sort $(VMS)))
|
||||
|
||||
help: SPACE = 1
|
||||
help: help/distro help/ve help/vm; @:
|
||||
|
17
lib/vm.mk
Normal file
17
lib/vm.mk
Normal file
@ -0,0 +1,17 @@
|
||||
# step 2: build up virtual machine's configuration
|
||||
|
||||
ifndef MKIMAGE_PROFILES
|
||||
$(error this makefile is designed to be included in toplevel one)
|
||||
endif
|
||||
|
||||
ifeq (vm,$(IMAGE_CLASS))
|
||||
|
||||
#vm/.bare: profile/bare use/bootloader/grub
|
||||
vm/.bare: profile/bare
|
||||
@$(call add,BASE_PACKAGES,basesystem interactivesystem lilo passwd shadow-utils e2fsprogs mingetty)
|
||||
@$(call set,KFLAVOURS,std-def)
|
||||
|
||||
vm/bare: vm/.bare
|
||||
@$(call add,BASE_PACKAGES,apt)
|
||||
|
||||
endif
|
8
main.mk
8
main.mk
@ -34,15 +34,19 @@ include lib/*.mk
|
||||
include conf.d/*.mk
|
||||
include features.in/*/config.mk
|
||||
|
||||
# starts to look copypastey
|
||||
DISTRO_TARGETS := $(shell sed -n 's,^\(distro/[^:.]\+\):.*$$,\1,p' \
|
||||
lib/distro.mk $(wildcard conf.d/*.mk) | sort -u)
|
||||
VE_TARGETS := $(shell sed -n 's,^\(ve/[^:.]\+\):.*$$,\1,p' \
|
||||
lib/ve.mk $(wildcard conf.d/*.mk) | sort -u)
|
||||
VM_TARGETS := $(shell sed -n 's,^\(vm/[^:.]\+\):.*$$,\1,p' \
|
||||
lib/vm.mk $(wildcard conf.d/*.mk) | sort -u)
|
||||
DISTROS := $(call addsuffices,$(DISTRO_EXTS),$(DISTRO_TARGETS))
|
||||
VES := $(call addsuffices,$(VE_EXTS),$(VE_TARGETS))
|
||||
IMAGES := $(DISTROS) $(VES)
|
||||
VMS := $(call addsuffices,$(VM_EXTS),$(VM_TARGETS))
|
||||
IMAGES := $(DISTROS) $(VES) $(VMS)
|
||||
|
||||
.PHONY: $(IMAGES) $(DISTRO_TARGETS) $(VE_TARGETS)
|
||||
.PHONY: $(IMAGES) $(DISTRO_TARGETS) $(VE_TARGETS) $(VM_TARGETS)
|
||||
.PHONY: debug everything help space
|
||||
|
||||
### duplicate but still needed
|
||||
|
Loading…
Reference in New Issue
Block a user