parent
37c2e05062
commit
a93073e0be
@ -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:
|
If you already have Go, Qemu, Vagrant and Docker installed, there's cross-platform installation checklist:
|
||||||
|
|
||||||
$ go get github.com/jollheef/out-of-tree
|
$ go get github.com/jollheef/out-of-tree
|
||||||
$ cd $GOPATH/src/github.com/jollheef/out-of-tree
|
$ cd $GOPATH/src/github.com/jollheef/out-of-tree/tools/qemu-debian-img/
|
||||||
$ cd tools/qemu-debian-img/
|
$ ./bootstrap.sh
|
||||||
$ vagrant up && vagrant destroy -f
|
|
||||||
$ cd ../kernel-factory
|
$ cd ../kernel-factory
|
||||||
$ rm -rf {Debian,CentOS,Ubuntu/{14.04,18.04}} # speed up :)
|
$ rm -rf {Debian,CentOS,Ubuntu/{14.04,18.04}} # speed up :)
|
||||||
$ ./bootstrap.sh
|
$ ./bootstrap.sh
|
||||||
|
@ -15,26 +15,23 @@ Features:
|
|||||||
|
|
||||||
First of all we need to generate rootfs for run qemu.
|
First of all we need to generate rootfs for run qemu.
|
||||||
|
|
||||||
#### GNU/Linux
|
#### Install qemu and docker
|
||||||
|
|
||||||
$ sudo apt install -y debootstrap qemu
|
##### GNU/Linux
|
||||||
$ sudo qemu-debian-img generate sid.img
|
|
||||||
|
|
||||||
#### macOS
|
$ sudo apt install -y qemu docker
|
||||||
|
|
||||||
|
##### macOS
|
||||||
|
|
||||||
Note: qemu on macOS since v2.12 (24 April 2018) supports Hypervisor.framework.
|
Note: qemu on macOS since v2.12 (24 April 2018) supports Hypervisor.framework.
|
||||||
|
|
||||||
$ brew install qemu
|
$ brew install qemu
|
||||||
|
$ brew cask install docker
|
||||||
|
|
||||||
Because it's a very complicated to debootstrap qemu images from macOS,
|
#### Generate image
|
||||||
preferred way is to use Vagrant with any hypervisor.
|
|
||||||
|
|
||||||
$ brew cask install vagrant
|
$ cd $GOPATH/src/github.com/jollheef/out-of-tree/tools/qemu-debian-img
|
||||||
$ vagrant plugin install vagrant-vbguest
|
$ ./bootstrap.sh
|
||||||
$ 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.
|
|
||||||
|
|
||||||
### Fill configuration file
|
### Fill configuration file
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
package qemukernel
|
package qemukernel
|
||||||
|
|
||||||
const testConfigVmlinuz = "../tools/qemu-debian-img/vmlinuz-bionic"
|
const testConfigVmlinuz = "../tools/qemu-debian-img/ubuntu1804.vmlinuz"
|
||||||
const testConfigInitrd = "../tools/qemu-debian-img/initrd-bionic"
|
const testConfigInitrd = "../tools/qemu-debian-img/ubuntu1804.initrd"
|
||||||
const testConfigRootfs = "../tools/qemu-debian-img/bionic.img"
|
const testConfigRootfs = "../tools/qemu-debian-img/ubuntu1804.img"
|
||||||
const testConfigSampleKo = "../tools/qemu-debian-img/sample.ko"
|
const testConfigSampleKo = "../tools/qemu-debian-img/ubuntu1804.ko"
|
||||||
|
4
tools/qemu-debian-img/.gitignore
vendored
4
tools/qemu-debian-img/.gitignore
vendored
@ -1,6 +1,6 @@
|
|||||||
*.img
|
*.img
|
||||||
*.log
|
*.log
|
||||||
vmlinuz*
|
*vmlinuz*
|
||||||
initrd*
|
*initrd*
|
||||||
*.ko
|
*.ko
|
||||||
.vagrant
|
.vagrant
|
||||||
|
35
tools/qemu-debian-img/Dockerfile
Normal file
35
tools/qemu-debian-img/Dockerfile
Normal file
@ -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
|
@ -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
|
|
22
tools/qemu-debian-img/Vagrantfile
vendored
22
tools/qemu-debian-img/Vagrantfile
vendored
@ -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
|
|
7
tools/qemu-debian-img/bootstrap.sh
Executable file
7
tools/qemu-debian-img/bootstrap.sh
Executable file
@ -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'
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
17
tools/qemu-debian-img/setup.sh
Executable file
17
tools/qemu-debian-img/setup.sh
Executable file
@ -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
|
Loading…
Reference in New Issue
Block a user