Qemu debian image generator
This commit is contained in:
parent
d723d1a8f5
commit
e923c7c3c8
181
tools/qemu-debian-img/main.go
Normal file
181
tools/qemu-debian-img/main.go
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
// Copyright 2018 Mikhail Klementev. All rights reserved.
|
||||||
|
// Use of this source code is governed by a GPLv3 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"+
|
||||||
|
" && echo PermitEmptyPasswords yes >> /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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user