mirror of
https://github.com/linka-cloud/d2vm.git
synced 2024-11-21 15:26:24 +00:00
add grub-efi support
* tests: increase timeout * ci: split e2e tests Signed-off-by: Adphi <philippe.adrien.nousse@gmail.com>
This commit is contained in:
parent
d4c3476031
commit
a41bbdb745
62
.github/workflows/ci.yaml
vendored
62
.github/workflows/ci.yaml
vendored
@ -45,9 +45,17 @@ jobs:
|
||||
- name: Run tests
|
||||
run: git --no-pager diff --exit-code HEAD~1 HEAD **/**.go templates/ || make tests
|
||||
|
||||
e2e-tests:
|
||||
name: End to end Tests
|
||||
templates-tests:
|
||||
name: Test Templates
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
image:
|
||||
- ubuntu
|
||||
- debian
|
||||
- kalilinux
|
||||
- alpine
|
||||
- centos
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
@ -70,6 +78,53 @@ jobs:
|
||||
- name: Setup dependencies
|
||||
run: sudo apt update && sudo apt install -y util-linux udev parted e2fsprogs mount tar extlinux qemu-utils qemu-system
|
||||
|
||||
- name: Share cache with other actions
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/go/pkg/mod
|
||||
/tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-tests-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-tests-
|
||||
|
||||
- name: Run tests
|
||||
run: git --no-pager diff --exit-code HEAD~1 HEAD **/**.go templates/ || IMAGE=${{ matrix.image }} make test-templates
|
||||
|
||||
|
||||
e2e-tests:
|
||||
name: End to end Tests
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
image:
|
||||
- alpine:3.17
|
||||
- ubuntu:20.04
|
||||
- ubuntu:22.04
|
||||
- debian:10
|
||||
- debian:11
|
||||
- centos:8
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# fetching all tags is required for the Makefile to compute the right version
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: "1.20"
|
||||
|
||||
- name: Set up QEMU dependency
|
||||
uses: docker/setup-qemu-action@v1
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Setup dependencies
|
||||
run: sudo apt update && sudo apt install -y util-linux udev parted e2fsprogs mount tar extlinux qemu-utils qemu-system ovmf
|
||||
|
||||
- name: Share cache with other actions
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
@ -81,7 +136,7 @@ jobs:
|
||||
${{ runner.os }}-tests-
|
||||
|
||||
- name: Run end-to-end tests
|
||||
run: make e2e
|
||||
run: E2E_IMAGES=${{ matrix.image }} make e2e
|
||||
|
||||
docs-up-to-date:
|
||||
name: Docs up to date
|
||||
@ -224,6 +279,7 @@ jobs:
|
||||
if: startsWith(github.event.ref, 'refs/tags/v')
|
||||
needs:
|
||||
- tests
|
||||
- templates-tests
|
||||
- docs-up-to-date
|
||||
- build
|
||||
- e2e-tests
|
||||
|
@ -39,7 +39,6 @@ RUN apt-get update && \
|
||||
mount \
|
||||
tar \
|
||||
extlinux \
|
||||
grub2 \
|
||||
cryptsetup-bin \
|
||||
qemu-utils && \
|
||||
apt-get clean && \
|
||||
|
9
Makefile
9
Makefile
@ -64,10 +64,15 @@ docker-run:
|
||||
.PHONY: tests
|
||||
tests:
|
||||
@go generate ./...
|
||||
@go list .| xargs go test -exec sudo -count=1 -timeout 20m -v
|
||||
@go list .| xargs go test -exec sudo -count=1 -timeout 60m -v -skip TestConfig
|
||||
|
||||
.PHONY: test-templates
|
||||
test-templates:
|
||||
@go generate ./...
|
||||
@go test -exec sudo -count=1 -timeout 60m -v -run TestConfig/$(IMAGE)
|
||||
|
||||
e2e: docker-build .build
|
||||
@go test -v -exec sudo -count=1 -timeout 60m -ldflags "-X '$(MODULE).Version=$(VERSION)' -X '$(MODULE).BuildDate=$(shell date)'" ./e2e
|
||||
@go test -v -exec sudo -count=1 -timeout 60m -ldflags "-X '$(MODULE).Version=$(VERSION)' -X '$(MODULE).BuildDate=$(shell date)'" ./e2e -args -images $(E2E_IMAGES)
|
||||
|
||||
docs-up-to-date:
|
||||
@$(MAKE) cli-docs
|
||||
|
@ -61,7 +61,6 @@ Obviously, **Distroless** images are not supported.
|
||||
- mount
|
||||
- tar
|
||||
- extlinux (when using syslinux)
|
||||
- grub2 (when using grub)
|
||||
- qemu-utils
|
||||
- cryptsetup (when using LUKS)
|
||||
- [QEMU](https://www.qemu.org/download/#linux) (optional)
|
||||
@ -161,7 +160,7 @@ Flags:
|
||||
--append-to-cmdline string Extra kernel cmdline arguments to append to the generated one
|
||||
--boot-fs string Filesystem to use for the boot partition, ext4 or fat32
|
||||
--boot-size uint Size of the boot partition in MB (default 100)
|
||||
--bootloader string Bootloader to use: syslinux, grub (default "syslinux")
|
||||
--bootloader string Bootloader to use: syslinux, grub, grub-bios, grub-efi (default "syslinux")
|
||||
--force Override output qcow2 image
|
||||
-h, --help help for convert
|
||||
--keep-cache Keep the images after the build
|
||||
@ -318,7 +317,7 @@ Flags:
|
||||
--append-to-cmdline string Extra kernel cmdline arguments to append to the generated one
|
||||
--boot-fs string Filesystem to use for the boot partition, ext4 or fat32
|
||||
--boot-size uint Size of the boot partition in MB (default 100)
|
||||
--bootloader string Bootloader to use: syslinux, grub (default "syslinux")
|
||||
--bootloader string Bootloader to use: syslinux, grub, grub-bios, grub-efi (default "syslinux")
|
||||
--build-arg stringArray Set build-time variables
|
||||
-f, --file string Name of the Dockerfile
|
||||
--force Override output qcow2 image
|
||||
|
@ -38,5 +38,6 @@ type BootloaderProvider interface {
|
||||
}
|
||||
|
||||
type Bootloader interface {
|
||||
Validate(fs BootFS) error
|
||||
Setup(ctx context.Context, dev, root, cmdline string) error
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ func NewBuilder(ctx context.Context, workdir, imgTag, disk string, size uint64,
|
||||
}
|
||||
|
||||
if bootFS == "" {
|
||||
bootFS = FSExt4
|
||||
bootFS = BootFSExt4
|
||||
}
|
||||
|
||||
if err := bootFS.Validate(); err != nil {
|
||||
@ -146,6 +146,10 @@ func NewBuilder(ctx context.Context, workdir, imgTag, disk string, size uint64,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := bl.Validate(bootFS); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if size == 0 {
|
||||
size = 10 * uint64(datasize.GB)
|
||||
}
|
||||
|
@ -57,6 +57,18 @@ func validateFlags() error {
|
||||
logrus.Warnf("boot filesystem is set: enabling split boot")
|
||||
splitBoot = true
|
||||
}
|
||||
efi := bootloader == "grub-efi" || bootloader == "grub"
|
||||
if efi && !splitBoot {
|
||||
logrus.Warnf("grub-efi bootloader is set: enabling split boot")
|
||||
splitBoot = true
|
||||
}
|
||||
if efi && bootFS != "" && bootFS != "fat32" {
|
||||
return fmt.Errorf("grub-efi bootloader only supports fat32 boot filesystem")
|
||||
}
|
||||
if efi && bootFS == "" {
|
||||
logrus.Warnf("grub-efi bootloader is set: enabling fat32 boot filesystem")
|
||||
bootFS = "fat32"
|
||||
}
|
||||
if push && tag == "" {
|
||||
return fmt.Errorf("tag is required when pushing container disk image")
|
||||
}
|
||||
@ -82,7 +94,7 @@ func buildFlags() *pflag.FlagSet {
|
||||
flags.BoolVar(&splitBoot, "split-boot", false, "Split the boot partition from the root partition")
|
||||
flags.Uint64Var(&bootSize, "boot-size", 100, "Size of the boot partition in MB")
|
||||
flags.StringVar(&bootFS, "boot-fs", "", "Filesystem to use for the boot partition, ext4 or fat32")
|
||||
flags.StringVar(&bootloader, "bootloader", "syslinux", "Bootloader to use: syslinux, grub")
|
||||
flags.StringVar(&bootloader, "bootloader", "syslinux", "Bootloader to use: syslinux, grub, grub-bios, grub-efi")
|
||||
flags.StringVar(&luksPassword, "luks-password", "", "Password to use for the LUKS encrypted root partition. If not set, the root partition will not be encrypted")
|
||||
flags.BoolVar(&keepCache, "keep-cache", false, "Keep the images after the build")
|
||||
return flags
|
||||
|
@ -28,6 +28,7 @@ var (
|
||||
arch string
|
||||
cpus uint
|
||||
mem uint
|
||||
bios string
|
||||
qemuCmd string
|
||||
qemuDetached bool
|
||||
networking string
|
||||
@ -71,6 +72,8 @@ func init() {
|
||||
flags.UintVar(&cpus, "cpus", 1, "Number of CPUs")
|
||||
flags.UintVar(&mem, "mem", 1024, "Amount of memory in MB")
|
||||
|
||||
flags.StringVar(&bios, "bios", "", "Path to the optional bios binary")
|
||||
|
||||
// Backend configuration
|
||||
flags.StringVar(&qemuCmd, "qemu", "", "Path to the qemu binary (otherwise look in $PATH)")
|
||||
flags.BoolVar(&qemuDetached, "detached", false, "Set qemu container to run in the background")
|
||||
@ -105,6 +108,7 @@ func Qemu(cmd *cobra.Command, args []string) {
|
||||
qemu.WithStdin(os.Stdin),
|
||||
qemu.WithStdout(os.Stdout),
|
||||
qemu.WithStderr(os.Stderr),
|
||||
qemu.WithBios(bios),
|
||||
}
|
||||
if enableGUI {
|
||||
opts = append(opts, qemu.WithGUI())
|
||||
|
@ -29,19 +29,22 @@ import (
|
||||
"go.linka.cloud/d2vm/pkg/exec"
|
||||
)
|
||||
|
||||
func testConfig(t *testing.T, ctx context.Context, img string, config Config) {
|
||||
func testConfig(t *testing.T, ctx context.Context, name, img string, config Config, luks, grubBIOS, grubEFI bool) {
|
||||
require.NoError(t, docker.Pull(ctx, img))
|
||||
tmpPath := filepath.Join(os.TempDir(), "d2vm-tests", strings.NewReplacer(":", "-", ".", "-").Replace(img))
|
||||
tmpPath := filepath.Join(os.TempDir(), "d2vm-tests", strings.NewReplacer(":", "-", ".", "-").Replace(name))
|
||||
require.NoError(t, os.MkdirAll(tmpPath, 0755))
|
||||
defer os.RemoveAll(tmpPath)
|
||||
logrus.Infof("inspecting image %s", img)
|
||||
r, err := FetchDockerImageOSRelease(ctx, img, tmpPath)
|
||||
r, err := FetchDockerImageOSRelease(ctx, img)
|
||||
require.NoError(t, err)
|
||||
defer docker.Remove(ctx, img)
|
||||
d, err := NewDockerfile(r, img, "root", "", false, false)
|
||||
if !r.SupportsLUKS() && luks {
|
||||
t.Skipf("LUKS not supported for %s", r.Version)
|
||||
}
|
||||
d, err := NewDockerfile(r, img, "root", "", luks, grubBIOS, grubEFI)
|
||||
require.NoError(t, err)
|
||||
logrus.Infof("docker image based on %s", d.Release.Name)
|
||||
p := filepath.Join(tmpPath, docker.FormatImgName(img))
|
||||
p := filepath.Join(tmpPath, docker.FormatImgName(name))
|
||||
dir := filepath.Dir(p)
|
||||
f, err := os.Create(p)
|
||||
require.NoError(t, err)
|
||||
@ -51,6 +54,10 @@ func testConfig(t *testing.T, ctx context.Context, img string, config Config) {
|
||||
logrus.Infof("building kernel enabled image")
|
||||
require.NoError(t, docker.Build(ctx, imgUUID, p, dir))
|
||||
defer docker.Remove(ctx, imgUUID)
|
||||
// we don't need to test the kernel location if grub is enabled
|
||||
if grubBIOS || grubEFI {
|
||||
return
|
||||
}
|
||||
require.NoError(t, docker.RunAndRemove(ctx, imgUUID, "test", "-f", config.Kernel))
|
||||
require.NoError(t, docker.RunAndRemove(ctx, imgUUID, "test", "-f", config.Initrd))
|
||||
}
|
||||
@ -116,13 +123,35 @@ func TestConfig(t *testing.T) {
|
||||
}
|
||||
exec.SetDebug(true)
|
||||
|
||||
names := []string{"luks", "grub-bios", "grub-efi"}
|
||||
bools := []bool{false, true}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.image, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
testConfig(t, ctx, test.image, test.config)
|
||||
for _, luks := range bools {
|
||||
for _, grubBIOS := range bools {
|
||||
for _, grubEFI := range bools {
|
||||
luks := luks
|
||||
grubBIOS := grubBIOS
|
||||
grubEFI := grubEFI
|
||||
n := []string{test.image}
|
||||
for i, v := range []bool{luks, grubBIOS, grubEFI} {
|
||||
if v {
|
||||
n = append(n, names[i])
|
||||
}
|
||||
}
|
||||
name := strings.Join(n, "-")
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
testConfig(t, ctx, name, test.image, test.config, luks, grubBIOS, grubEFI)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ func Convert(ctx context.Context, img string, opts ...ConvertOption) error {
|
||||
defer os.RemoveAll(tmpPath)
|
||||
|
||||
logrus.Infof("inspecting image %s", img)
|
||||
r, err := FetchDockerImageOSRelease(ctx, img, tmpPath)
|
||||
r, err := FetchDockerImageOSRelease(ctx, img)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -51,7 +51,7 @@ func Convert(ctx context.Context, img string, opts ...ConvertOption) error {
|
||||
}
|
||||
|
||||
if !o.raw {
|
||||
d, err := NewDockerfile(r, img, o.password, o.networkManager, o.luksPassword != "", o.bootLoader == "grub")
|
||||
d, err := NewDockerfile(r, img, o.password, o.networkManager, o.luksPassword != "", o.hasGrubBIOS(), o.hasGrubEFI())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -34,6 +34,14 @@ type convertOptions struct {
|
||||
keepCache bool
|
||||
}
|
||||
|
||||
func (o *convertOptions) hasGrubBIOS() bool {
|
||||
return o.bootLoader == "grub" || o.bootLoader == "grub-bios"
|
||||
}
|
||||
|
||||
func (o *convertOptions) hasGrubEFI() bool {
|
||||
return o.bootLoader == "grub" || o.bootLoader == "grub-efi"
|
||||
}
|
||||
|
||||
func WithSize(size uint64) ConvertOption {
|
||||
return func(o *convertOptions) {
|
||||
o.size = size
|
||||
|
@ -65,16 +65,21 @@ type Dockerfile struct {
|
||||
Release OSRelease
|
||||
NetworkManager NetworkManager
|
||||
Luks bool
|
||||
Grub bool
|
||||
GrubBIOS bool
|
||||
GrubEFI bool
|
||||
tmpl *template.Template
|
||||
}
|
||||
|
||||
func (d Dockerfile) Grub() bool {
|
||||
return d.GrubBIOS || d.GrubEFI
|
||||
}
|
||||
|
||||
func (d Dockerfile) Render(w io.Writer) error {
|
||||
return d.tmpl.Execute(w, d)
|
||||
}
|
||||
|
||||
func NewDockerfile(release OSRelease, img, password string, networkManager NetworkManager, luks, grub bool) (Dockerfile, error) {
|
||||
d := Dockerfile{Release: release, Image: img, Password: password, NetworkManager: networkManager, Luks: luks, Grub: grub}
|
||||
func NewDockerfile(release OSRelease, img, password string, networkManager NetworkManager, luks, grubBIOS, grubEFI bool) (Dockerfile, error) {
|
||||
d := Dockerfile{Release: release, Image: img, Password: password, NetworkManager: networkManager, Luks: luks, GrubBIOS: grubBIOS, GrubEFI: grubEFI}
|
||||
var net NetworkManager
|
||||
switch release.ID {
|
||||
case ReleaseDebian:
|
||||
|
@ -12,7 +12,7 @@ d2vm build [context directory] [flags]
|
||||
--append-to-cmdline string Extra kernel cmdline arguments to append to the generated one
|
||||
--boot-fs string Filesystem to use for the boot partition, ext4 or fat32
|
||||
--boot-size uint Size of the boot partition in MB (default 100)
|
||||
--bootloader string Bootloader to use: syslinux, grub (default "syslinux")
|
||||
--bootloader string Bootloader to use: syslinux, grub, grub-bios, grub-efi (default "syslinux")
|
||||
--build-arg stringArray Set build-time variables
|
||||
-f, --file string Name of the Dockerfile
|
||||
--force Override output qcow2 image
|
||||
|
@ -12,7 +12,7 @@ d2vm convert [docker image] [flags]
|
||||
--append-to-cmdline string Extra kernel cmdline arguments to append to the generated one
|
||||
--boot-fs string Filesystem to use for the boot partition, ext4 or fat32
|
||||
--boot-size uint Size of the boot partition in MB (default 100)
|
||||
--bootloader string Bootloader to use: syslinux, grub (default "syslinux")
|
||||
--bootloader string Bootloader to use: syslinux, grub, grub-bios, grub-efi (default "syslinux")
|
||||
--force Override output qcow2 image
|
||||
-h, --help help for convert
|
||||
--keep-cache Keep the images after the build
|
||||
|
@ -11,6 +11,7 @@ d2vm run qemu [options] [image-path] [flags]
|
||||
```
|
||||
--accel string Choose acceleration mode. Use 'tcg' to disable it. (default "kvm:tcg")
|
||||
--arch string Type of architecture to use, e.g. x86_64, aarch64, s390x (default "x86_64")
|
||||
--bios string Path to the optional bios binary
|
||||
--cpus uint Number of CPUs (default 1)
|
||||
--detached Set qemu container to run in the background
|
||||
--disk disk Disk config, may be repeated. [file=]path[,size=1G][,format=qcow2] (default [])
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"flag"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -36,6 +37,7 @@ import (
|
||||
type test struct {
|
||||
name string
|
||||
args []string
|
||||
efi bool
|
||||
}
|
||||
|
||||
type img struct {
|
||||
@ -43,14 +45,24 @@ type img struct {
|
||||
luks string
|
||||
}
|
||||
|
||||
var images = []img{
|
||||
{name: "alpine:3.17", luks: "Enter passphrase for /dev/sda2:"},
|
||||
{name: "ubuntu:20.04", luks: "Please unlock disk root:"},
|
||||
{name: "ubuntu:22.04", luks: "Please unlock disk root:"},
|
||||
{name: "debian:10", luks: "Please unlock disk root:"},
|
||||
{name: "debian:11", luks: "Please unlock disk root:"},
|
||||
{name: "centos:8", luks: "Please enter passphrase for disk"},
|
||||
}
|
||||
var (
|
||||
images = []img{
|
||||
{name: "alpine:3.17", luks: "Enter passphrase for /dev/sda2:"},
|
||||
{name: "ubuntu:20.04", luks: "Please unlock disk root:"},
|
||||
{name: "ubuntu:22.04", luks: "Please unlock disk root:"},
|
||||
{name: "debian:10", luks: "Please unlock disk root:"},
|
||||
{name: "debian:11", luks: "Please unlock disk root:"},
|
||||
{name: "centos:8", luks: "Please enter passphrase for disk"},
|
||||
}
|
||||
imgNames = func() []string {
|
||||
var imgs []string
|
||||
for _, img := range images {
|
||||
imgs = append(imgs, img.name)
|
||||
}
|
||||
return imgs
|
||||
}()
|
||||
imgs = flag.String("images", "", "comma separated list of images to test, must be one of: "+strings.Join(imgNames, ","))
|
||||
)
|
||||
|
||||
func TestConvert(t *testing.T) {
|
||||
require := require2.New(t)
|
||||
@ -62,6 +74,10 @@ func TestConvert(t *testing.T) {
|
||||
name: "split-boot",
|
||||
args: []string{"--split-boot"},
|
||||
},
|
||||
{
|
||||
name: "fat32",
|
||||
args: []string{"--split-boot", "--boot-fs=fat32"},
|
||||
},
|
||||
{
|
||||
name: "luks",
|
||||
args: []string{"--luks-password=root"},
|
||||
@ -69,13 +85,30 @@ func TestConvert(t *testing.T) {
|
||||
{
|
||||
name: "grub",
|
||||
args: []string{"--bootloader=grub"},
|
||||
efi: true,
|
||||
},
|
||||
{
|
||||
name: "grub-luks",
|
||||
args: []string{"--bootloader=grub", "--luks-password=root"},
|
||||
efi: true,
|
||||
},
|
||||
}
|
||||
|
||||
var testImgs []img
|
||||
imgs:
|
||||
for _, v := range strings.Split(*imgs, ",") {
|
||||
for _, img := range images {
|
||||
if img.name == v {
|
||||
testImgs = append(testImgs, img)
|
||||
continue imgs
|
||||
}
|
||||
}
|
||||
t.Fatalf("invalid image: %q, valid images: %s", v, strings.Join(imgNames, ","))
|
||||
}
|
||||
if len(testImgs) == 0 {
|
||||
testImgs = images
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@ -83,7 +116,7 @@ func TestConvert(t *testing.T) {
|
||||
require.NoError(os.MkdirAll(dir, os.ModePerm))
|
||||
|
||||
defer os.RemoveAll(dir)
|
||||
for _, img := range images {
|
||||
for _, img := range testImgs {
|
||||
t.Run(img.name, func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
@ -161,7 +194,11 @@ func TestConvert(t *testing.T) {
|
||||
cancel()
|
||||
}
|
||||
}()
|
||||
if err := qemu.Run(ctx, out, qemu.WithStdin(inr), qemu.WithStdout(io.MultiWriter(outw, os.Stdout)), qemu.WithStderr(io.Discard), qemu.WithMemory(2048)); err != nil && !success.Load() {
|
||||
opts := []qemu.Option{qemu.WithStdin(inr), qemu.WithStdout(io.MultiWriter(outw, os.Stdout)), qemu.WithStderr(io.Discard), qemu.WithMemory(2048), qemu.WithCPUs(2)}
|
||||
if tt.efi {
|
||||
opts = append(opts, qemu.WithBios("/usr/share/ovmf/OVMF.fd"))
|
||||
}
|
||||
if err := qemu.Run(ctx, out, opts...); err != nil && !success.Load() {
|
||||
t.Fatalf("failed to run qemu: %v", err)
|
||||
}
|
||||
})
|
||||
|
10
fs.go
10
fs.go
@ -21,8 +21,8 @@ import (
|
||||
type BootFS string
|
||||
|
||||
const (
|
||||
FSExt4 BootFS = "ext4"
|
||||
FSFat32 BootFS = "fat32"
|
||||
BootFSExt4 BootFS = "ext4"
|
||||
BootFSFat32 BootFS = "fat32"
|
||||
)
|
||||
|
||||
func (f BootFS) String() string {
|
||||
@ -30,11 +30,11 @@ func (f BootFS) String() string {
|
||||
}
|
||||
|
||||
func (f BootFS) IsExt() bool {
|
||||
return f == FSExt4
|
||||
return f == BootFSExt4
|
||||
}
|
||||
|
||||
func (f BootFS) IsFat() bool {
|
||||
return f == FSFat32
|
||||
return f == BootFSFat32
|
||||
}
|
||||
|
||||
func (f BootFS) IsSupported() bool {
|
||||
@ -50,7 +50,7 @@ func (f BootFS) Validate() error {
|
||||
|
||||
func (f BootFS) linux() string {
|
||||
switch f {
|
||||
case FSFat32:
|
||||
case BootFSFat32:
|
||||
return "vfat"
|
||||
default:
|
||||
return "ext4"
|
||||
|
77
grub.go
77
grub.go
@ -17,89 +17,54 @@ package d2vm
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
exec2 "os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"go.linka.cloud/d2vm/pkg/exec"
|
||||
)
|
||||
|
||||
const grubCfg = `GRUB_DEFAULT=0
|
||||
GRUB_HIDDEN_TIMEOUT=0
|
||||
GRUB_HIDDEN_TIMEOUT_QUIET=true
|
||||
GRUB_TIMEOUT=0
|
||||
GRUB_CMDLINE_LINUX_DEFAULT="%s"
|
||||
GRUB_CMDLINE_LINUX=""
|
||||
GRUB_TERMINAL=console
|
||||
`
|
||||
|
||||
type grub struct {
|
||||
name string
|
||||
c Config
|
||||
r OSRelease
|
||||
*grubCommon
|
||||
}
|
||||
|
||||
func (g grub) Validate(fs BootFS) error {
|
||||
switch fs {
|
||||
case BootFSFat32:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("grub only supports fat32 boot filesystem due to grub-efi")
|
||||
}
|
||||
}
|
||||
|
||||
func (g grub) Setup(ctx context.Context, dev, root string, cmdline string) error {
|
||||
logrus.Infof("setting up grub bootloader")
|
||||
if err := os.WriteFile(filepath.Join(root, "etc", "default", "grub"), []byte(fmt.Sprintf(grubCfg, cmdline)), perm); err != nil {
|
||||
clean, err := g.prepare(ctx, dev, root, cmdline)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Join(root, "boot", g.name), os.ModePerm); err != nil {
|
||||
defer clean()
|
||||
if err := g.install(ctx, "--target=x86_64-efi", "--efi-directory=/boot", "--no-nvram", "--removable", "--no-floppy"); err != nil {
|
||||
return err
|
||||
}
|
||||
mounts := []string{"dev", "proc", "sys"}
|
||||
var unmounts []string
|
||||
defer func() {
|
||||
for _, v := range unmounts {
|
||||
if err := exec.Run(ctx, "umount", filepath.Join(root, v)); err != nil {
|
||||
logrus.Errorf("failed to unmount /%s: %s", v, err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
for _, v := range mounts {
|
||||
if err := exec.Run(ctx, "mount", "-o", "bind", "/"+v, filepath.Join(root, v)); err != nil {
|
||||
return err
|
||||
}
|
||||
unmounts = append(unmounts, v)
|
||||
}
|
||||
|
||||
if err := exec.Run(ctx, "chroot", root, g.name+"-install", "--target=i386-pc", "--boot-directory", "/boot", dev); err != nil {
|
||||
if err := g.install(ctx, "--target=i386-pc", "--boot-directory=/boot", dev); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := exec.Run(ctx, "chroot", root, g.name+"-mkconfig", "-o", "/boot/"+g.name+"/grub.cfg"); err != nil {
|
||||
if err := g.mkconfig(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type grubBootloaderProvider struct {
|
||||
type grubProvider struct {
|
||||
config Config
|
||||
}
|
||||
|
||||
func (g grubBootloaderProvider) New(c Config, r OSRelease) (Bootloader, error) {
|
||||
name := "grub"
|
||||
if r.ID == "centos" {
|
||||
name = "grub2"
|
||||
}
|
||||
if _, err := exec2.LookPath("grub-install"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := exec2.LookPath("grub-mkconfig"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return grub{
|
||||
name: name,
|
||||
c: c,
|
||||
r: r,
|
||||
}, nil
|
||||
func (g grubProvider) New(c Config, r OSRelease) (Bootloader, error) {
|
||||
return grub{grubCommon: newGrubCommon(c, r)}, nil
|
||||
}
|
||||
|
||||
func (g grubBootloaderProvider) Name() string {
|
||||
func (g grubProvider) Name() string {
|
||||
return "grub"
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterBootloaderProvider(grubBootloaderProvider{})
|
||||
RegisterBootloaderProvider(grubProvider{})
|
||||
}
|
||||
|
61
grub_bios.go
Normal file
61
grub_bios.go
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright 2023 Linka Cloud All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package d2vm
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type grubBios struct {
|
||||
*grubCommon
|
||||
}
|
||||
|
||||
func (g grubBios) Validate(_ BootFS) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g grubBios) Setup(ctx context.Context, dev, root string, cmdline string) error {
|
||||
logrus.Infof("setting up grub bootloader")
|
||||
clean, err := g.prepare(ctx, dev, root, cmdline)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer clean()
|
||||
if err := g.install(ctx, "--target=i386-pc", "--boot-directory=/boot", dev); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.mkconfig(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type grubBiosProvider struct {
|
||||
config Config
|
||||
}
|
||||
|
||||
func (g grubBiosProvider) New(c Config, r OSRelease) (Bootloader, error) {
|
||||
return grubBios{grubCommon: newGrubCommon(c, r)}, nil
|
||||
}
|
||||
|
||||
func (g grubBiosProvider) Name() string {
|
||||
return "grub-bios"
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterBootloaderProvider(grubBiosProvider{})
|
||||
}
|
102
grub_common.go
Normal file
102
grub_common.go
Normal file
@ -0,0 +1,102 @@
|
||||
// Copyright 2023 Linka Cloud All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package d2vm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"go.linka.cloud/d2vm/pkg/exec"
|
||||
)
|
||||
|
||||
const grubCfg = `GRUB_DEFAULT=0
|
||||
GRUB_HIDDEN_TIMEOUT=0
|
||||
GRUB_HIDDEN_TIMEOUT_QUIET=true
|
||||
GRUB_TIMEOUT=0
|
||||
GRUB_CMDLINE_LINUX_DEFAULT="%s"
|
||||
GRUB_CMDLINE_LINUX=""
|
||||
GRUB_TERMINAL=console
|
||||
`
|
||||
|
||||
type grubCommon struct {
|
||||
name string
|
||||
c Config
|
||||
r OSRelease
|
||||
root string
|
||||
dev string
|
||||
}
|
||||
|
||||
func newGrubCommon(c Config, r OSRelease) *grubCommon {
|
||||
name := "grub"
|
||||
if r.ID == "centos" {
|
||||
name = "grub2"
|
||||
}
|
||||
return &grubCommon{
|
||||
name: name,
|
||||
c: c,
|
||||
r: r,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *grubCommon) prepare(ctx context.Context, dev, root, cmdline string) (clean func(), err error) {
|
||||
g.dev = dev
|
||||
g.root = root
|
||||
if err = os.WriteFile(filepath.Join(root, "etc", "default", "grub"), []byte(fmt.Sprintf(grubCfg, cmdline)), perm); err != nil {
|
||||
return
|
||||
}
|
||||
if err = os.MkdirAll(filepath.Join(root, "boot", g.name), os.ModePerm); err != nil {
|
||||
return
|
||||
}
|
||||
mounts := []string{"dev", "proc", "sys"}
|
||||
var unmounts []string
|
||||
clean = func() {
|
||||
for _, v := range unmounts {
|
||||
if err := exec.Run(ctx, "umount", filepath.Join(root, v)); err != nil {
|
||||
logrus.Errorf("failed to unmount /%s: %s", v, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
clean()
|
||||
}
|
||||
}()
|
||||
for _, v := range mounts {
|
||||
if err = exec.Run(ctx, "mount", "-o", "bind", "/"+v, filepath.Join(root, v)); err != nil {
|
||||
return
|
||||
}
|
||||
unmounts = append(unmounts, v)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (g *grubCommon) install(ctx context.Context, args ...string) error {
|
||||
if g.dev == "" || g.root == "" {
|
||||
return fmt.Errorf("grubCommon not prepared")
|
||||
}
|
||||
args = append([]string{g.root, g.name + "-install"}, args...)
|
||||
return exec.Run(ctx, "chroot", args...)
|
||||
}
|
||||
|
||||
func (g *grubCommon) mkconfig(ctx context.Context) error {
|
||||
if g.dev == "" || g.root == "" {
|
||||
return fmt.Errorf("grubCommon not prepared")
|
||||
}
|
||||
return exec.Run(ctx, "chroot", g.root, g.name+"-mkconfig", "-o", "/boot/"+g.name+"/grub.cfg")
|
||||
}
|
67
grub_efi.go
Normal file
67
grub_efi.go
Normal file
@ -0,0 +1,67 @@
|
||||
// Copyright 2023 Linka Cloud All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package d2vm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type grubEFI struct {
|
||||
*grubCommon
|
||||
}
|
||||
|
||||
func (g grubEFI) Validate(fs BootFS) error {
|
||||
switch fs {
|
||||
case BootFSFat32:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("grub-efi only supports fat32 boot filesystem")
|
||||
}
|
||||
}
|
||||
|
||||
func (g grubEFI) Setup(ctx context.Context, dev, root string, cmdline string) error {
|
||||
logrus.Infof("setting up grub-efi bootloader")
|
||||
clean, err := g.prepare(ctx, dev, root, cmdline)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer clean()
|
||||
if err := g.install(ctx, "--target=x86_64-efi", "--efi-directory=/boot", "--no-nvram", "--removable", "--no-floppy"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.mkconfig(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type grubEFIProvider struct {
|
||||
config Config
|
||||
}
|
||||
|
||||
func (g grubEFIProvider) New(c Config, r OSRelease) (Bootloader, error) {
|
||||
return grubEFI{grubCommon: newGrubCommon(c, r)}, nil
|
||||
}
|
||||
|
||||
func (g grubEFIProvider) Name() string {
|
||||
return "grub-efi"
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterBootloaderProvider(grubEFIProvider{})
|
||||
}
|
@ -16,12 +16,8 @@ package d2vm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -107,40 +103,8 @@ func ParseOSRelease(s string) (OSRelease, error) {
|
||||
return o, nil
|
||||
}
|
||||
|
||||
const (
|
||||
osReleaseDockerfile = `
|
||||
FROM {{ . }}
|
||||
|
||||
ENTRYPOINT [""]
|
||||
|
||||
CMD ["/bin/cat", "/etc/os-release"]
|
||||
`
|
||||
)
|
||||
|
||||
var (
|
||||
osReleaseDockerfileTemplate = template.Must(template.New("osrelease.Dockerfile").Parse(osReleaseDockerfile))
|
||||
)
|
||||
|
||||
func FetchDockerImageOSRelease(ctx context.Context, img string, tmpPath string) (OSRelease, error) {
|
||||
d := filepath.Join(tmpPath, "osrelease.Dockerfile")
|
||||
f, err := os.Create(d)
|
||||
if err != nil {
|
||||
return OSRelease{}, err
|
||||
}
|
||||
defer f.Close()
|
||||
if err := osReleaseDockerfileTemplate.Execute(f, img); err != nil {
|
||||
return OSRelease{}, err
|
||||
}
|
||||
imgTag := fmt.Sprintf("os-release-%s", img)
|
||||
if err := docker.Cmd(ctx, "image", "build", "-t", imgTag, "-f", d, tmpPath); err != nil {
|
||||
return OSRelease{}, err
|
||||
}
|
||||
defer func() {
|
||||
if err := docker.Cmd(ctx, "image", "rm", imgTag); err != nil {
|
||||
logrus.WithError(err).Error("failed to cleanup OSRelease Docker Image")
|
||||
}
|
||||
}()
|
||||
o, _, err := docker.CmdOut(ctx, "run", "--rm", "-i", imgTag)
|
||||
func FetchDockerImageOSRelease(ctx context.Context, img string) (OSRelease, error) {
|
||||
o, _, err := docker.CmdOut(ctx, "run", "--rm", "-i", "--entrypoint", "cat", img, "/etc/os-release")
|
||||
if err != nil {
|
||||
return OSRelease{}, err
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ type config struct {
|
||||
arch string
|
||||
cpus uint
|
||||
memory uint
|
||||
bios string
|
||||
accel string
|
||||
detached bool
|
||||
qemuBinPath string
|
||||
@ -92,6 +93,12 @@ func WithMemory(memory uint) Option {
|
||||
}
|
||||
}
|
||||
|
||||
func WithBios(bios string) Option {
|
||||
return func(c *config) {
|
||||
c.bios = bios
|
||||
}
|
||||
}
|
||||
|
||||
func WithAccel(accel string) Option {
|
||||
return func(c *config) {
|
||||
c.accel = accel
|
||||
|
@ -197,6 +197,10 @@ func (c *config) buildQemuCmdline() ([]string, error) {
|
||||
qemuArgs = append(qemuArgs, "-m", fmt.Sprintf("%d", c.memory))
|
||||
qemuArgs = append(qemuArgs, "-uuid", c.uuid.String())
|
||||
|
||||
if c.bios != "" {
|
||||
qemuArgs = append(qemuArgs, "-bios", c.bios)
|
||||
}
|
||||
|
||||
// Need to specify the vcpu type when running qemu on arm64 platform, for security reason,
|
||||
// the vcpu should be "host" instead of other names such as "cortex-a53"...
|
||||
if c.arch == "aarch64" {
|
||||
|
@ -50,6 +50,10 @@ type syslinux struct {
|
||||
mbrBin string
|
||||
}
|
||||
|
||||
func (s syslinux) Validate(_ BootFS) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s syslinux) Setup(ctx context.Context, dev, root string, cmdline string) error {
|
||||
logrus.Infof("setting up syslinux bootloader")
|
||||
if err := exec.Run(ctx, "extlinux", "--install", filepath.Join(root, "boot")); err != nil {
|
||||
|
@ -2,8 +2,7 @@ FROM {{ .Image }}
|
||||
|
||||
USER root
|
||||
|
||||
RUN apk update --no-cache && \
|
||||
apk add \
|
||||
RUN apk add --no-cache \
|
||||
util-linux \
|
||||
linux-virt \
|
||||
{{- if ge .Release.VersionID "3.17" }}
|
||||
@ -31,13 +30,21 @@ iface eth0 inet dhcp\n\
|
||||
' > /etc/network/interfaces
|
||||
{{ end }}
|
||||
|
||||
{{- if .Luks }}
|
||||
{{ if .Luks }}
|
||||
RUN apk add --no-cache cryptsetup && \
|
||||
source /etc/mkinitfs/mkinitfs.conf && \
|
||||
echo "features=\"${features} cryptsetup\"" > /etc/mkinitfs/mkinitfs.conf && \
|
||||
mkinitfs $(ls /lib/modules)
|
||||
{{- end }}
|
||||
|
||||
{{- if .Grub }} \
|
||||
RUN apk add --no-cache grub grub-bios
|
||||
# we need to keep that at the end, because after it, we can't install packages without error anymore due to grub hooks
|
||||
{{- if .Grub }}
|
||||
RUN apk add --no-cache \
|
||||
{{- if .GrubBIOS }}
|
||||
grub-bios \
|
||||
{{- end }}
|
||||
{{- if .GrubEFI }}
|
||||
grub-efi \
|
||||
{{- end }}
|
||||
grub
|
||||
{{- end }}
|
||||
|
@ -7,24 +7,23 @@ RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* && \
|
||||
|
||||
RUN yum update -y
|
||||
|
||||
# See https://bugzilla.redhat.com/show_bug.cgi?id=1917213
|
||||
RUN yum install -y \
|
||||
kernel \
|
||||
systemd \
|
||||
NetworkManager \
|
||||
{{- if .Grub }}
|
||||
{{- if .GrubBIOS }}
|
||||
grub2 \
|
||||
{{- end }}
|
||||
{{- if .GrubEFI }}
|
||||
grub2 grub2-efi-x64 grub2-efi-x64-modules \
|
||||
{{- end }}
|
||||
e2fsprogs \
|
||||
sudo && \
|
||||
systemctl enable NetworkManager && \
|
||||
systemctl unmask systemd-remount-fs.service && \
|
||||
systemctl unmask getty.target
|
||||
|
||||
{{- if not .Grub }}
|
||||
RUN cd /boot && \
|
||||
mv $(find . -name 'vmlinuz-*') /boot/vmlinuz && \
|
||||
mv $(find . -name 'initramfs-*.img') /boot/initrd.img
|
||||
{{- end }}
|
||||
systemctl unmask getty.target && \
|
||||
find /boot -type l -exec rm {} \;
|
||||
|
||||
{{ if .Luks }}
|
||||
RUN yum install -y cryptsetup && \
|
||||
@ -34,3 +33,9 @@ RUN dracut --no-hostonly --regenerate-all --force
|
||||
{{ end }}
|
||||
|
||||
{{ if .Password }}RUN echo "root:{{ .Password }}" | chpasswd {{ end }}
|
||||
|
||||
{{- if not .Grub }}
|
||||
RUN cd /boot && \
|
||||
mv $(find . -name 'vmlinuz-*') /boot/vmlinuz && \
|
||||
mv $(find . -name 'initramfs-*.img') /boot/initrd.img
|
||||
{{- end }}
|
||||
|
@ -10,21 +10,23 @@ RUN echo "deb http://archive.debian.org/debian stretch main" > /etc/apt/sources.
|
||||
echo "deb-src http://archive.debian.org/debian-security stretch/updates main" >> /etc/apt/sources.list
|
||||
{{- end }}
|
||||
|
||||
RUN apt-get -y update && \
|
||||
RUN apt-get update && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends \
|
||||
linux-image-amd64 && \
|
||||
find /boot -type l -exec rm {} \;
|
||||
|
||||
{{- if not .Grub }}
|
||||
RUN mv $(find /boot -name 'vmlinuz-*') /boot/vmlinuz && \
|
||||
mv $(find /boot -name 'initrd.img-*') /boot/initrd.img
|
||||
{{- end }}
|
||||
|
||||
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||
systemd-sysv \
|
||||
systemd \
|
||||
{{- if .Grub }}
|
||||
grub2 \
|
||||
grub-common \
|
||||
grub2-common \
|
||||
{{- end }}
|
||||
{{- if .GrubBIOS }}
|
||||
grub-pc-bin \
|
||||
{{- end }}
|
||||
{{- if .GrubEFI }}
|
||||
grub-efi-amd64-bin \
|
||||
{{- end }}
|
||||
dbus \
|
||||
iproute2 \
|
||||
@ -65,3 +67,9 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends cr
|
||||
echo "CRYPTSETUP=y" >> /etc/cryptsetup-initramfs/conf-hook && \
|
||||
update-initramfs -u -v
|
||||
{{- end }}
|
||||
|
||||
# needs to be after update-initramfs
|
||||
{{- if not .Grub }}
|
||||
RUN mv $(find /boot -name 'vmlinuz-*') /boot/vmlinuz && \
|
||||
mv $(find /boot -name 'initrd.img-*') /boot/initrd.img
|
||||
{{- end }}
|
||||
|
@ -2,14 +2,21 @@ FROM {{ .Image }}
|
||||
|
||||
USER root
|
||||
|
||||
RUN apt-get update -y && \
|
||||
RUN apt-get update && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends \
|
||||
linux-image-virtual \
|
||||
initramfs-tools \
|
||||
systemd-sysv \
|
||||
systemd \
|
||||
{{- if .Grub }}
|
||||
grub2 \
|
||||
grub-common \
|
||||
grub2-common \
|
||||
{{- end }}
|
||||
{{- if .GrubBIOS }}
|
||||
grub-pc-bin \
|
||||
{{- end }}
|
||||
{{- if .GrubEFI }}
|
||||
grub-efi-amd64-bin \
|
||||
{{- end }}
|
||||
dbus \
|
||||
isc-dhcp-client \
|
||||
@ -17,11 +24,6 @@ RUN apt-get update -y && \
|
||||
iputils-ping && \
|
||||
find /boot -type l -exec rm {} \;
|
||||
|
||||
{{- if not .Grub }}
|
||||
RUN mv $(find /boot -name 'vmlinuz-*') /boot/vmlinuz && \
|
||||
mv $(find /boot -name 'initrd.img-*') /boot/initrd.img
|
||||
{{- end }}
|
||||
|
||||
RUN systemctl preset-all
|
||||
|
||||
{{ if .Password }}RUN echo "root:{{ .Password }}" | chpasswd {{ end }}
|
||||
@ -54,3 +56,9 @@ iface eth0 inet dhcp\n\
|
||||
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends cryptsetup-initramfs && \
|
||||
update-initramfs -u -v
|
||||
{{- end }}
|
||||
|
||||
# needs to be after update-initramfs
|
||||
{{- if not .Grub }}
|
||||
RUN mv $(find /boot -name 'vmlinuz-*') /boot/vmlinuz && \
|
||||
mv $(find /boot -name 'initrd.img-*') /boot/initrd.img
|
||||
{{- end }}
|
||||
|
Loading…
Reference in New Issue
Block a user