From a93073e0be127af743497ee490f69c3fa050d708 Mon Sep 17 00:00:00 2001 From: Mikhail Klementev Date: Thu, 25 Oct 2018 23:38:12 +0000 Subject: [PATCH] Use Docker instead of Vagrant for generate images Fixes #2 --- README.md | 5 +- qemu/README.md | 21 ++-- qemu/test.config.go | 8 +- tools/qemu-debian-img/.gitignore | 4 +- tools/qemu-debian-img/Dockerfile | 35 ++++++ tools/qemu-debian-img/TODO | 5 - tools/qemu-debian-img/Vagrantfile | 22 ---- tools/qemu-debian-img/bootstrap.sh | 7 ++ tools/qemu-debian-img/main.go | 183 ----------------------------- tools/qemu-debian-img/setup.sh | 17 +++ 10 files changed, 76 insertions(+), 231 deletions(-) create mode 100644 tools/qemu-debian-img/Dockerfile delete mode 100644 tools/qemu-debian-img/TODO delete mode 100644 tools/qemu-debian-img/Vagrantfile create mode 100755 tools/qemu-debian-img/bootstrap.sh delete mode 100644 tools/qemu-debian-img/main.go create mode 100755 tools/qemu-debian-img/setup.sh diff --git a/README.md b/README.md index ef0a854..4ee7a30 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,8 @@ Read [Qemu API](qemu/README.md). If you already have Go, Qemu, Vagrant and Docker installed, there's cross-platform installation checklist: $ go get github.com/jollheef/out-of-tree - $ cd $GOPATH/src/github.com/jollheef/out-of-tree - $ cd tools/qemu-debian-img/ - $ vagrant up && vagrant destroy -f + $ cd $GOPATH/src/github.com/jollheef/out-of-tree/tools/qemu-debian-img/ + $ ./bootstrap.sh $ cd ../kernel-factory $ rm -rf {Debian,CentOS,Ubuntu/{14.04,18.04}} # speed up :) $ ./bootstrap.sh diff --git a/qemu/README.md b/qemu/README.md index b06215b..60c7587 100644 --- a/qemu/README.md +++ b/qemu/README.md @@ -15,26 +15,23 @@ Features: First of all we need to generate rootfs for run qemu. -#### GNU/Linux +#### Install qemu and docker - $ sudo apt install -y debootstrap qemu - $ sudo qemu-debian-img generate sid.img +##### GNU/Linux -#### macOS + $ sudo apt install -y qemu docker + +##### macOS Note: qemu on macOS since v2.12 (24 April 2018) supports Hypervisor.framework. $ brew install qemu + $ brew cask install docker -Because it's a very complicated to debootstrap qemu images from macOS, -preferred way is to use Vagrant with any hypervisor. +#### Generate image - $ brew cask install vagrant - $ vagrant plugin install vagrant-vbguest - $ cd $GOPATH/src/github.com/jollheef/out-of-tree/qemu/tools/qemu-debian-image - $ vagrant up && vagrant destroy -f - -bionic.img, vmlinuz-bionic and initrd-bionic will be created in current directory. + $ cd $GOPATH/src/github.com/jollheef/out-of-tree/tools/qemu-debian-img + $ ./bootstrap.sh ### Fill configuration file diff --git a/qemu/test.config.go b/qemu/test.config.go index 49171e7..44f6e2b 100644 --- a/qemu/test.config.go +++ b/qemu/test.config.go @@ -4,7 +4,7 @@ package qemukernel -const testConfigVmlinuz = "../tools/qemu-debian-img/vmlinuz-bionic" -const testConfigInitrd = "../tools/qemu-debian-img/initrd-bionic" -const testConfigRootfs = "../tools/qemu-debian-img/bionic.img" -const testConfigSampleKo = "../tools/qemu-debian-img/sample.ko" +const testConfigVmlinuz = "../tools/qemu-debian-img/ubuntu1804.vmlinuz" +const testConfigInitrd = "../tools/qemu-debian-img/ubuntu1804.initrd" +const testConfigRootfs = "../tools/qemu-debian-img/ubuntu1804.img" +const testConfigSampleKo = "../tools/qemu-debian-img/ubuntu1804.ko" diff --git a/tools/qemu-debian-img/.gitignore b/tools/qemu-debian-img/.gitignore index e774386..354481c 100644 --- a/tools/qemu-debian-img/.gitignore +++ b/tools/qemu-debian-img/.gitignore @@ -1,6 +1,6 @@ *.img *.log -vmlinuz* -initrd* +*vmlinuz* +*initrd* *.ko .vagrant diff --git a/tools/qemu-debian-img/Dockerfile b/tools/qemu-debian-img/Dockerfile new file mode 100644 index 0000000..12b9553 --- /dev/null +++ b/tools/qemu-debian-img/Dockerfile @@ -0,0 +1,35 @@ +# Copyright 2018 Mikhail Klementev. All rights reserved. +# Use of this source code is governed by a AGPLv3 license +# (or later) that can be found in the LICENSE file. +# +# Usage: +# +# $ docker build -t gen-ubuntu1804-image . +# $ docker run --privileged -v $(pwd):/shared -t gen-ubuntu1804-image +# +# centos7.img will be created in current directory. You can change $(pwd) to +# different directory to use different destination for image. +# +FROM ubuntu:18.04 + +ENV DEBIAN_FRONTEND=noninteractive +RUN apt update +RUN apt install -y debootstrap qemu +RUN apt install -y linux-image-generic + +ENV TMPDIR=/tmp/ubuntu +ENV IMAGEDIR=/tmp/image +ENV IMAGE=/shared/ubuntu1804.img +ENV REPOSITORY=http://archive.ubuntu.com/ubuntu +ENV RELEASE=bionic + +RUN mkdir $IMAGEDIR + +# Must be runned with --privileged because of /dev/loop +CMD debootstrap --include=openssh-server $RELEASE $TMPDIR $REPOSITORY && \ + /shared/setup.sh $TMPDIR && \ + qemu-img create $IMAGE 2G && \ + mkfs.ext4 -F $IMAGE && \ + mount -o loop $IMAGE $IMAGEDIR && \ + cp -a $TMPDIR/* $IMAGEDIR/ && \ + umount $IMAGEDIR diff --git a/tools/qemu-debian-img/TODO b/tools/qemu-debian-img/TODO deleted file mode 100644 index 49bf53d..0000000 --- a/tools/qemu-debian-img/TODO +++ /dev/null @@ -1,5 +0,0 @@ -# TODO - -* Add ability to bootstrap centos image, rename tool to qemu-bootstrap-img - - yum --installroot=/chroot --releasever=7 --disablerepo='*' --enablerepo=base install centos-release diff --git a/tools/qemu-debian-img/Vagrantfile b/tools/qemu-debian-img/Vagrantfile deleted file mode 100644 index ec6d90a..0000000 --- a/tools/qemu-debian-img/Vagrantfile +++ /dev/null @@ -1,22 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -Vagrant.configure("2") do |config| - config.vm.box = "ubuntu/bionic64" - - config.vm.provision "shell", inline: <<-SHELL - apt-get update - apt-get install -y debootstrap qemu golang - mkdir qemu-debian-img && cd qemu-debian-img - cp /vagrant/main.go ./ - GOBIN=/usr/bin go get ./ - export REPO=http://archive.ubuntu.com/ubuntu - for RELEASE in trusty xenial bionic; do \ - qemu-debian-img generate --repository=$REPO --release=$RELEASE $RELEASE.img - cp $RELEASE.img /vagrant/ - done - cp /boot/vmlinuz-* /vagrant/vmlinuz-bionic - cp /boot/initrd* /vagrant/initrd-bionic - cp /lib/modules/`uname -r`/kernel/lib/test_static_key_base.ko /vagrant/sample.ko - SHELL -end diff --git a/tools/qemu-debian-img/bootstrap.sh b/tools/qemu-debian-img/bootstrap.sh new file mode 100755 index 0000000..d468240 --- /dev/null +++ b/tools/qemu-debian-img/bootstrap.sh @@ -0,0 +1,7 @@ +#!/bin/sh -eux +docker build -t gen-ubuntu1804-image . +RUN="docker run --privileged -v $(pwd):/shared -t gen-ubuntu1804-image" +$RUN # generate image +$RUN sh -c 'cp /vmlinuz /shared/ubuntu1804.vmlinuz' +$RUN sh -c 'cp /initrd.img /shared/ubuntu1804.initrd' +$RUN sh -c 'cp $(find /lib/modules -name test_static_key_base.ko) /shared/ubuntu1804.ko' diff --git a/tools/qemu-debian-img/main.go b/tools/qemu-debian-img/main.go deleted file mode 100644 index 2cfff5c..0000000 --- a/tools/qemu-debian-img/main.go +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2018 Mikhail Klementev. All rights reserved. -// Use of this source code is governed by a AGPLv3 license -// (or later) that can be found in the LICENSE file. - -package main - -import ( - "errors" - "io/ioutil" - "log" - "net/http" - "os" - "os/user" - "regexp" - "strings" - - system "github.com/jollheef/go-system" - kingpin "gopkg.in/alecthomas/kingpin.v2" -) - -func matchBody(url, pattern string) bool { - resp, err := http.Get(url) - if err != nil { - return false - } - defer resp.Body.Close() - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return false - } - - matched, err := regexp.MatchString(pattern, string(body)) - if err != nil { - return false - } - if !matched { - return false - } - - return true -} - -func isAptCacherExists(url string) bool { - return matchBody(url, "Apt-Cacher") -} - -func runInChroot(chroot, cmd string) (string, string, int, error) { - return system.System("chroot", chroot, "/bin/sh", "-c", cmd) -} - -func generateImage(repo, release, path, size string) (err error) { - log.Println("Check current user") - usr, err := user.Current() - if err != nil { - return - } - if usr.Name != "root" { - err = errors.New("Run as root is required") - return - } - - log.Println("Create qcow2 image") - stdout, stderr, _, err := system.System("qemu-img", "create", path, size) - if err != nil { - log.Println(stdout, stderr) - return - } - - log.Println("Create ext4 file system") - stdout, stderr, _, err = system.System("mkfs.ext4", "-F", path) - if err != nil { - log.Println(stdout, stderr) - return - } - - log.Println("Create temporary directory") - stdout, stderr, _, err = system.System("mktemp", "-d") - if err != nil { - log.Println(stdout, stderr) - return - } - tmpdir := strings.TrimSpace(stdout) - defer func() { - log.Println("Remove temporary directory") - err := os.RemoveAll(tmpdir) - if err != nil { - log.Println(err) - } - }() - - log.Println("Mount qemu image") - stdout, stderr, _, err = system.System("mount", "-o", "loop", path, tmpdir) - if err != nil { - log.Println(stdout, stderr) - return - } - defer func() { - log.Println("Umount qemu image") - stdout, stderr, _, err := system.System("umount", tmpdir) - if err != nil { - log.Println(err, stdout, stderr) - } - }() - - log.Println("debootstrap (may be more than 10-15 minutes)") - stdout, stderr, _, err = system.System("debootstrap", - "--include=openssh-server", - release, tmpdir, repo) - if err != nil { - log.Println(stdout, stderr) - return - } - - log.Println("Create new user") - stdout, stderr, _, err = runInChroot(tmpdir, "useradd -m user") - if err != nil { - log.Println(stdout, stderr) - return - } - - log.Println("Login without password") - stdout, stderr, _, err = runInChroot(tmpdir, "passwd -d root") - if err != nil { - log.Println(stdout, stderr) - return - } - stdout, stderr, _, err = runInChroot(tmpdir, "passwd -d user") - if err != nil { - log.Println(stdout, stderr) - return - } - - log.Println("Allow ssh login without password (NOTE: fixed sshd pam.d)") - stdout, stderr, _, err = runInChroot(tmpdir, - "echo auth sufficient pam_permit.so > /etc/pam.d/sshd"+ - " && sed -i '/PermitEmptyPasswords/d' /etc/ssh/sshd_config"+ - " && echo PermitEmptyPasswords yes >> /etc/ssh/sshd_config"+ - " && sed -i '/PermitRootLogin/d' /etc/ssh/sshd_config"+ - " && echo PermitRootLogin yes >> /etc/ssh/sshd_config") - if err != nil { - log.Println(stdout, stderr) - return - } - - log.Println("Add dhclient to rc.local") - stdout, stderr, _, err = runInChroot(tmpdir, - "echo '#!/bin/sh\ndhclient' > /etc/rc.local"+ - " && chmod +x /etc/rc.local") - if err != nil { - log.Println(stdout, stderr) - return - } - - return -} - -func main() { - generate := kingpin.Command("generate", "Generate qemu image") - repository := generate.Flag("repository", "Debian/ubuntu repository").Default( - "deb.debian.org/debian").String() - aptCacherURL := generate.Flag("apt-cacher", "Local apt cacher url").Default( - "http://localhost:3142/").String() - release := generate.Flag("release", "Debian/ubuntu release name").Default( - "sid").String() - size := generate.Flag("size", "Image size").Default("8G").String() - path := generate.Arg("path", "Generated image path").Required().String() - - switch kingpin.Parse() { - case "generate": - repo := *repository - if isAptCacherExists(*aptCacherURL) { - log.Println("Use local apt cache") - repo = *aptCacherURL + "/" + repo - } - log.Println("Repository:", repo) - - err := generateImage(repo, *release, *path, *size) - if err != nil { - log.Fatalln(err) - } - } -} diff --git a/tools/qemu-debian-img/setup.sh b/tools/qemu-debian-img/setup.sh new file mode 100755 index 0000000..6779283 --- /dev/null +++ b/tools/qemu-debian-img/setup.sh @@ -0,0 +1,17 @@ +#!/bin/sh -eux +# Copyright 2018 Mikhail Klementev. All rights reserved. +# Use of this source code is governed by a AGPLv3 license +# (or later) that can be found in the LICENSE file. +TMPDIR=$1 +chroot $TMPDIR /bin/sh -c 'useradd -m user' +sed -i 's/root:\*:/root::/' $TMPDIR/etc/shadow +sed -i 's/user:!!:/user::/' $TMPDIR/etc/shadow +echo auth sufficient pam_permit.so > $TMPDIR/etc/pam.d/sshd +sed -i '/PermitEmptyPasswords/d' $TMPDIR/etc/ssh/sshd_config +echo PermitEmptyPasswords yes >> $TMPDIR/etc/ssh/sshd_config +sed -i '/PermitRootLogin/d' $TMPDIR/etc/ssh/sshd_config +echo PermitRootLogin yes >> $TMPDIR/etc/ssh/sshd_config + +echo '#!/bin/sh' > $TMPDIR/etc/rc.local +echo 'dhclient' >> $TMPDIR/etc/rc.local +chmod +x $TMPDIR/etc/rc.local