mirror of
https://github.com/linka-cloud/d2vm.git
synced 2024-11-22 07:46:25 +00:00
chore: bootloader abtraction
Signed-off-by: Adphi <philippe.adrien.nousse@gmail.com>
This commit is contained in:
parent
ec33a7ad74
commit
a003e176f5
2
.gitignore
vendored
2
.gitignore
vendored
@ -11,6 +11,8 @@ dist/
|
||||
images
|
||||
/d2vm
|
||||
/examples/build
|
||||
/examples/full/demo-magic
|
||||
/examples/full/inside
|
||||
.goreleaser.yaml
|
||||
docs/build
|
||||
docs-src
|
||||
|
4
Makefile
4
Makefile
@ -87,7 +87,7 @@ install: docker-build
|
||||
|
||||
.build:
|
||||
@go generate ./...
|
||||
@go build -o d2vm -ldflags "-s -w -X '$(MODULE).Version=$(VERSION)' -X '$(MODULE).BuildDate=$(shell date)'" ./cmd/d2vm
|
||||
@CGO_ENABLED=0 go build -o d2vm -ldflags "-s -w -X '$(MODULE).Version=$(VERSION)' -X '$(MODULE).BuildDate=$(shell date)'" ./cmd/d2vm
|
||||
|
||||
.PHONY: build-snapshot
|
||||
build-snapshot: bin
|
||||
@ -116,7 +116,7 @@ completions: .build
|
||||
.PHONY: examples
|
||||
examples: build-dev
|
||||
@mkdir -p examples/build
|
||||
@for f in $$(find examples -type f -name '*Dockerfile' -maxdepth 1); do \
|
||||
@for f in $$(find examples -maxdepth 1 -type f -name '*Dockerfile'); do \
|
||||
echo "Building $$f"; \
|
||||
./d2vm build -o examples/build/$$(basename $$f|cut -d'.' -f1).qcow2 -p root -f $$f examples --force; \
|
||||
done
|
||||
|
42
bootloader.go
Normal file
42
bootloader.go
Normal file
@ -0,0 +1,42 @@
|
||||
// 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"
|
||||
)
|
||||
|
||||
var bootloaderProviders = map[string]BootloaderProvider{}
|
||||
|
||||
func RegisterBootloaderProvider(provider BootloaderProvider) {
|
||||
bootloaderProviders[provider.Name()] = provider
|
||||
}
|
||||
|
||||
func BootloaderByName(name string) (BootloaderProvider, error) {
|
||||
if p, ok := bootloaderProviders[name]; ok {
|
||||
return p, nil
|
||||
}
|
||||
return nil, fmt.Errorf("bootloader provider %s not found", name)
|
||||
}
|
||||
|
||||
type BootloaderProvider interface {
|
||||
New(c Config) (Bootloader, error)
|
||||
Name() string
|
||||
}
|
||||
|
||||
type Bootloader interface {
|
||||
Setup(ctx context.Context, raw, path, cmdline string) error
|
||||
}
|
132
builder.go
132
builder.go
@ -41,72 +41,10 @@ ff02::1 ip6-allnodes
|
||||
ff02::2 ip6-allrouters
|
||||
ff02::3 ip6-allhosts
|
||||
`
|
||||
syslinuxCfgUbuntu = `DEFAULT linux
|
||||
SAY Now booting the kernel from SYSLINUX...
|
||||
LABEL linux
|
||||
KERNEL /boot/vmlinuz
|
||||
APPEND ro root=UUID=%s initrd=/boot/initrd.img net.ifnames=0 console=tty0 console=ttyS0,115200n8 %s
|
||||
`
|
||||
syslinuxCfgDebian = `DEFAULT linux
|
||||
SAY Now booting the kernel from SYSLINUX...
|
||||
LABEL linux
|
||||
KERNEL /vmlinuz
|
||||
APPEND ro root=UUID=%s initrd=/initrd.img net.ifnames=0 console=tty0 console=ttyS0,115200n8 %s
|
||||
`
|
||||
syslinuxCfgAlpine = `DEFAULT linux
|
||||
SAY Now booting the kernel from SYSLINUX...
|
||||
LABEL linux
|
||||
KERNEL /boot/vmlinuz-virt
|
||||
APPEND ro root=UUID=%s rootfstype=ext4 initrd=/boot/initramfs-virt console=ttyS0,115200 %s
|
||||
`
|
||||
syslinuxCfgCentOS = `DEFAULT linux
|
||||
SAY Now booting the kernel from SYSLINUX...
|
||||
LABEL linux
|
||||
KERNEL /boot/vmlinuz
|
||||
APPEND ro root=UUID=%s initrd=/boot/initrd.img net.ifnames=0 console=tty0 console=ttyS0,115200n8 %s
|
||||
`
|
||||
)
|
||||
|
||||
var (
|
||||
formats = []string{"qcow2", "qed", "raw", "vdi", "vhd", "vmdk"}
|
||||
|
||||
mbrPaths = []string{
|
||||
// debian path
|
||||
"/usr/lib/syslinux/mbr/mbr.bin",
|
||||
// ubuntu path
|
||||
"/usr/lib/EXTLINUX/mbr.bin",
|
||||
// alpine path
|
||||
"/usr/share/syslinux/mbr.bin",
|
||||
// centos path
|
||||
"/usr/share/syslinux/mbr.bin",
|
||||
// archlinux path
|
||||
"/usr/lib/syslinux/bios/mbr.bin",
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
perm os.FileMode = 0644
|
||||
)
|
||||
|
||||
func sysconfig(osRelease OSRelease) (string, error) {
|
||||
switch osRelease.ID {
|
||||
case ReleaseUbuntu:
|
||||
if osRelease.VersionID < "20.04" {
|
||||
return syslinuxCfgDebian, nil
|
||||
}
|
||||
return syslinuxCfgUbuntu, nil
|
||||
case ReleaseDebian:
|
||||
return syslinuxCfgDebian, nil
|
||||
case ReleaseKali:
|
||||
return syslinuxCfgDebian, nil
|
||||
case ReleaseAlpine:
|
||||
return syslinuxCfgAlpine, nil
|
||||
case ReleaseCentOS:
|
||||
return syslinuxCfgCentOS, nil
|
||||
default:
|
||||
return "", fmt.Errorf("%s: distribution not supported", osRelease.ID)
|
||||
}
|
||||
}
|
||||
var formats = []string{"qcow2", "qed", "raw", "vdi", "vhd", "vmdk"}
|
||||
|
||||
type Builder interface {
|
||||
Build(ctx context.Context) (err error)
|
||||
@ -115,6 +53,8 @@ type Builder interface {
|
||||
|
||||
type builder struct {
|
||||
osRelease OSRelease
|
||||
config Config
|
||||
bootloader Bootloader
|
||||
|
||||
src string
|
||||
img *image
|
||||
@ -128,8 +68,6 @@ type builder struct {
|
||||
splitBoot bool
|
||||
bootSize uint64
|
||||
|
||||
mbrPath string
|
||||
|
||||
loDevice string
|
||||
bootPart string
|
||||
rootPart string
|
||||
@ -145,7 +83,7 @@ type builder struct {
|
||||
cmdLineExtra string
|
||||
}
|
||||
|
||||
func NewBuilder(ctx context.Context, workdir, imgTag, disk string, size uint64, osRelease OSRelease, format string, cmdLineExtra string, splitBoot bool, bootSize uint64, luksPassword string) (Builder, error) {
|
||||
func NewBuilder(ctx context.Context, workdir, imgTag, disk string, size uint64, osRelease OSRelease, format string, cmdLineExtra string, splitBoot bool, bootSize uint64, luksPassword string, bootLoader string) (Builder, error) {
|
||||
if err := checkDependencies(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -176,16 +114,24 @@ func NewBuilder(ctx context.Context, workdir, imgTag, disk string, size uint64,
|
||||
return nil, fmt.Errorf("boot partition size must be less than the disk size")
|
||||
}
|
||||
|
||||
mbrBin := ""
|
||||
for _, v := range mbrPaths {
|
||||
if _, err := os.Stat(v); err == nil {
|
||||
mbrBin = v
|
||||
break
|
||||
if bootLoader == "" {
|
||||
bootLoader = "syslinux"
|
||||
}
|
||||
|
||||
config, err := osRelease.Config()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if mbrBin == "" {
|
||||
return nil, fmt.Errorf("unable to find syslinux's mbr.bin path")
|
||||
|
||||
blp, err := BootloaderByName(bootLoader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bl, err := blp.New(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if size == 0 {
|
||||
size = 10 * uint64(datasize.GB)
|
||||
}
|
||||
@ -207,12 +153,13 @@ func NewBuilder(ctx context.Context, workdir, imgTag, disk string, size uint64,
|
||||
// }
|
||||
b := &builder{
|
||||
osRelease: osRelease,
|
||||
config: config,
|
||||
bootloader: bl,
|
||||
img: img,
|
||||
diskRaw: filepath.Join(workdir, disk+".d2vm.raw"),
|
||||
diskOut: filepath.Join(workdir, disk+"."+format),
|
||||
format: f,
|
||||
size: size,
|
||||
mbrPath: mbrBin,
|
||||
mntPoint: filepath.Join(workdir, "/mnt"),
|
||||
cmdLineExtra: cmdLineExtra,
|
||||
splitBoot: splitBoot,
|
||||
@ -259,9 +206,6 @@ func (b *builder) Build(ctx context.Context) (err error) {
|
||||
if err = b.unmountImg(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = b.setupMBR(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = b.convert2Img(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -490,45 +434,27 @@ func (b *builder) setupRootFS(ctx context.Context) (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (b *builder) installKernel(ctx context.Context) error {
|
||||
logrus.Infof("installing linux kernel")
|
||||
if err := exec.Run(ctx, "extlinux", "--install", b.chPath("/boot")); err != nil {
|
||||
return err
|
||||
}
|
||||
sysconfig, err := sysconfig(b.osRelease)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var cfg string
|
||||
func (b *builder) cmdline(_ context.Context) string {
|
||||
if b.isLuksEnabled() {
|
||||
switch b.osRelease.ID {
|
||||
case ReleaseAlpine:
|
||||
cfg = fmt.Sprintf(sysconfig, b.rootUUID, fmt.Sprintf("%s root=/dev/mapper/root cryptdm=root", b.cmdLineExtra))
|
||||
cfg = strings.Replace(cfg, "root=UUID="+b.rootUUID, "cryptroot=UUID="+b.cryptUUID, 1)
|
||||
return b.config.Cmdline(RootUUID(b.rootUUID), "root=/dev/mapper/root", "cryptdm=root", "cryptroot=UUID="+b.cryptUUID, b.cmdLineExtra)
|
||||
case ReleaseCentOS:
|
||||
cfg = fmt.Sprintf(sysconfig, b.rootUUID, fmt.Sprintf("%s rd.luks.name=UUID=%s rd.luks.uuid=%s rd.luks.crypttab=0", b.cmdLineExtra, b.rootUUID, b.cryptUUID))
|
||||
return b.config.Cmdline(RootUUID(b.rootUUID), "rd.luks.name=UUID="+b.rootUUID+" rd.luks.uuid="+b.cryptUUID+" rd.luks.crypttab=0", b.cmdLineExtra)
|
||||
default:
|
||||
// for some versions of debian, the cryptopts parameter MUST contain all the following: target,source,key,opts...
|
||||
// see https://salsa.debian.org/cryptsetup-team/cryptsetup/-/blob/debian/buster/debian/functions
|
||||
// and https://cryptsetup-team.pages.debian.net/cryptsetup/README.initramfs.html
|
||||
cfg = fmt.Sprintf(sysconfig, b.rootUUID, fmt.Sprintf("%s root=/dev/mapper/root cryptopts=target=root,source=UUID=%s,key=none,luks", b.cmdLineExtra, b.cryptUUID))
|
||||
cfg = strings.Replace(cfg, "root=UUID="+b.rootUUID, "", 1)
|
||||
return b.config.Cmdline(nil, "root=/dev/mapper/root", "cryptopts=target=root,source=UUID="+b.cryptUUID+",key=none,luks", b.cmdLineExtra)
|
||||
}
|
||||
} else {
|
||||
cfg = fmt.Sprintf(sysconfig, b.rootUUID, b.cmdLineExtra)
|
||||
return b.config.Cmdline(RootUUID(b.rootUUID), b.cmdLineExtra)
|
||||
}
|
||||
if err := b.chWriteFile("/boot/syslinux.cfg", cfg, perm); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *builder) setupMBR(ctx context.Context) error {
|
||||
logrus.Infof("writing MBR")
|
||||
if err := exec.Run(ctx, "dd", fmt.Sprintf("if=%s", b.mbrPath), fmt.Sprintf("of=%s", b.diskRaw), "bs=440", "count=1", "conv=notrunc"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
func (b *builder) installKernel(ctx context.Context) error {
|
||||
logrus.Infof("installing linux kernel")
|
||||
return b.bootloader.Setup(ctx, b.diskRaw, b.chPath("/boot"), b.cmdline(ctx))
|
||||
}
|
||||
|
||||
func (b *builder) convert2Img(ctx context.Context) error {
|
||||
|
89
config.go
Normal file
89
config.go
Normal file
@ -0,0 +1,89 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
configUbuntu = Config{
|
||||
Kernel: "/boot/vmlinuz",
|
||||
Initrd: "/boot/initrd.img",
|
||||
}
|
||||
configDebian = Config{
|
||||
Kernel: "/vmlinuz",
|
||||
Initrd: "/initrd.img",
|
||||
}
|
||||
configAlpine = Config{
|
||||
Kernel: "/boot/vmlinuz-virt",
|
||||
Initrd: "/boot/initramfs-virt",
|
||||
}
|
||||
configCentOS = Config{
|
||||
Kernel: "/boot/vmlinuz",
|
||||
Initrd: "/boot/initrd.img",
|
||||
}
|
||||
)
|
||||
|
||||
type Root interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
type RootUUID string
|
||||
|
||||
func (r RootUUID) String() string {
|
||||
return "UUID=" + string(r)
|
||||
}
|
||||
|
||||
type RootPath string
|
||||
|
||||
func (r RootPath) String() string {
|
||||
return string(r)
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Kernel string
|
||||
Initrd string
|
||||
}
|
||||
|
||||
func (c Config) Cmdline(root Root, args ...string) string {
|
||||
var r string
|
||||
if root != nil {
|
||||
r = fmt.Sprintf("root=%s", root.String())
|
||||
}
|
||||
return fmt.Sprintf("ro initrd=%s %s net.ifnames=0 rootfstype=ext4 console=tty0 console=ttyS0,115200n8 %s", c.Initrd, r, strings.Join(args, " "))
|
||||
}
|
||||
|
||||
func (r OSRelease) Config() (Config, error) {
|
||||
switch r.ID {
|
||||
case ReleaseUbuntu:
|
||||
if r.VersionID < "20.04" {
|
||||
return configDebian, nil
|
||||
}
|
||||
return configUbuntu, nil
|
||||
case ReleaseDebian:
|
||||
return configDebian, nil
|
||||
case ReleaseKali:
|
||||
return configDebian, nil
|
||||
case ReleaseAlpine:
|
||||
return configAlpine, nil
|
||||
case ReleaseCentOS:
|
||||
return configCentOS, nil
|
||||
default:
|
||||
return Config{}, fmt.Errorf("%s: distribution not supported", r.ID)
|
||||
|
||||
}
|
||||
}
|
@ -23,14 +23,13 @@ import (
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"go.linka.cloud/d2vm/pkg/docker"
|
||||
"go.linka.cloud/d2vm/pkg/exec"
|
||||
)
|
||||
|
||||
func testSysconfig(t *testing.T, ctx context.Context, img, sysconf, kernel, initrd string) {
|
||||
func testConfig(t *testing.T, ctx context.Context, img string, config Config) {
|
||||
require.NoError(t, docker.Pull(ctx, img))
|
||||
tmpPath := filepath.Join(os.TempDir(), "d2vm-tests", strings.NewReplacer(":", "-", ".", "-").Replace(img))
|
||||
require.NoError(t, os.MkdirAll(tmpPath, 0755))
|
||||
@ -39,9 +38,6 @@ func testSysconfig(t *testing.T, ctx context.Context, img, sysconf, kernel, init
|
||||
r, err := FetchDockerImageOSRelease(ctx, img, tmpPath)
|
||||
require.NoError(t, err)
|
||||
defer docker.Remove(ctx, img)
|
||||
sys, err := sysconfig(r)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, sysconf, sys)
|
||||
d, err := NewDockerfile(r, img, "root", "", false)
|
||||
require.NoError(t, err)
|
||||
logrus.Infof("docker image based on %s", d.Release.Name)
|
||||
@ -55,95 +51,67 @@ func testSysconfig(t *testing.T, ctx context.Context, img, sysconf, kernel, init
|
||||
logrus.Infof("building kernel enabled image")
|
||||
require.NoError(t, docker.Build(ctx, imgUUID, p, dir))
|
||||
defer docker.Remove(ctx, imgUUID)
|
||||
require.NoError(t, docker.RunAndRemove(ctx, imgUUID, "test", "-f", kernel))
|
||||
require.NoError(t, docker.RunAndRemove(ctx, imgUUID, "test", "-f", initrd))
|
||||
require.NoError(t, docker.RunAndRemove(ctx, imgUUID, "test", "-f", config.Kernel))
|
||||
require.NoError(t, docker.RunAndRemove(ctx, imgUUID, "test", "-f", config.Initrd))
|
||||
}
|
||||
|
||||
func TestSyslinuxCfg(t *testing.T) {
|
||||
func TestConfig(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := []struct {
|
||||
image string
|
||||
kernel string
|
||||
initrd string
|
||||
sysconfig string
|
||||
config Config
|
||||
}{
|
||||
{
|
||||
image: "ubuntu:18.04",
|
||||
kernel: "/vmlinuz",
|
||||
initrd: "/initrd.img",
|
||||
sysconfig: syslinuxCfgDebian,
|
||||
config: configDebian,
|
||||
},
|
||||
{
|
||||
image: "ubuntu:20.04",
|
||||
kernel: "/boot/vmlinuz",
|
||||
initrd: "/boot/initrd.img",
|
||||
sysconfig: syslinuxCfgUbuntu,
|
||||
config: configUbuntu,
|
||||
},
|
||||
{
|
||||
image: "ubuntu:22.04",
|
||||
kernel: "/boot/vmlinuz",
|
||||
initrd: "/boot/initrd.img",
|
||||
sysconfig: syslinuxCfgUbuntu,
|
||||
config: configUbuntu,
|
||||
},
|
||||
{
|
||||
image: "ubuntu:latest",
|
||||
kernel: "/boot/vmlinuz",
|
||||
initrd: "/boot/initrd.img",
|
||||
sysconfig: syslinuxCfgUbuntu,
|
||||
config: configUbuntu,
|
||||
},
|
||||
{
|
||||
image: "debian:9",
|
||||
kernel: "/vmlinuz",
|
||||
initrd: "/initrd.img",
|
||||
sysconfig: syslinuxCfgDebian,
|
||||
config: configDebian,
|
||||
},
|
||||
{
|
||||
image: "debian:10",
|
||||
kernel: "/vmlinuz",
|
||||
initrd: "/initrd.img",
|
||||
sysconfig: syslinuxCfgDebian,
|
||||
config: configDebian,
|
||||
},
|
||||
{
|
||||
image: "debian:11",
|
||||
kernel: "/vmlinuz",
|
||||
initrd: "/initrd.img",
|
||||
sysconfig: syslinuxCfgDebian,
|
||||
config: configDebian,
|
||||
},
|
||||
{
|
||||
image: "debian:latest",
|
||||
kernel: "/vmlinuz",
|
||||
initrd: "/initrd.img",
|
||||
sysconfig: syslinuxCfgDebian,
|
||||
config: configDebian,
|
||||
},
|
||||
{
|
||||
image: "kalilinux/kali-rolling:latest",
|
||||
kernel: "/vmlinuz",
|
||||
initrd: "/initrd.img",
|
||||
sysconfig: syslinuxCfgDebian,
|
||||
config: configDebian,
|
||||
},
|
||||
{
|
||||
image: "alpine:3.16",
|
||||
kernel: "/boot/vmlinuz-virt",
|
||||
initrd: "/boot/initramfs-virt",
|
||||
sysconfig: syslinuxCfgAlpine,
|
||||
config: configAlpine,
|
||||
},
|
||||
{
|
||||
image: "alpine",
|
||||
kernel: "/boot/vmlinuz-virt",
|
||||
initrd: "/boot/initramfs-virt",
|
||||
sysconfig: syslinuxCfgAlpine,
|
||||
config: configAlpine,
|
||||
},
|
||||
{
|
||||
image: "centos:8",
|
||||
kernel: "/boot/vmlinuz",
|
||||
initrd: "/boot/initrd.img",
|
||||
sysconfig: syslinuxCfgCentOS,
|
||||
config: configCentOS,
|
||||
},
|
||||
{
|
||||
image: "centos:latest",
|
||||
kernel: "/boot/vmlinuz",
|
||||
initrd: "/boot/initrd.img",
|
||||
sysconfig: syslinuxCfgCentOS,
|
||||
config: configCentOS,
|
||||
},
|
||||
}
|
||||
exec.SetDebug(true)
|
||||
@ -154,7 +122,7 @@ func TestSyslinuxCfg(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
testSysconfig(t, ctx, test.image, test.sysconfig, test.kernel, test.initrd)
|
||||
testConfig(t, ctx, test.image, test.config)
|
||||
})
|
||||
}
|
||||
}
|
@ -88,7 +88,7 @@ func Convert(ctx context.Context, img string, opts ...ConvertOption) error {
|
||||
if format == "" {
|
||||
format = "raw"
|
||||
}
|
||||
b, err := NewBuilder(ctx, tmpPath, imgUUID, "", o.size, r, format, o.cmdLineExtra, o.splitBoot, o.bootSize, o.luksPassword)
|
||||
b, err := NewBuilder(ctx, tmpPath, imgUUID, "", o.size, r, format, o.cmdLineExtra, o.splitBoot, o.bootSize, o.luksPassword, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
92
syslinux.go
Normal file
92
syslinux.go
Normal file
@ -0,0 +1,92 @@
|
||||
// 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 syslinuxCfg = `DEFAULT linux
|
||||
SAY Now booting the kernel from SYSLINUX...
|
||||
LABEL linux
|
||||
KERNEL %s
|
||||
APPEND %s
|
||||
`
|
||||
|
||||
var mbrPaths = []string{
|
||||
// debian path
|
||||
"/usr/lib/syslinux/mbr/mbr.bin",
|
||||
// ubuntu path
|
||||
"/usr/lib/EXTLINUX/mbr.bin",
|
||||
// alpine path
|
||||
"/usr/share/syslinux/mbr.bin",
|
||||
// centos path
|
||||
"/usr/share/syslinux/mbr.bin",
|
||||
// archlinux path
|
||||
"/usr/lib/syslinux/bios/mbr.bin",
|
||||
}
|
||||
|
||||
type syslinux struct {
|
||||
c Config
|
||||
mbrBin string
|
||||
}
|
||||
|
||||
func (s syslinux) Setup(ctx context.Context, raw, path string, cmdline string) error {
|
||||
if err := exec.Run(ctx, "extlinux", "--install", path); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(path, "syslinux.cfg"), []byte(fmt.Sprintf(syslinuxCfg, s.c.Kernel, cmdline)), perm); err != nil {
|
||||
return err
|
||||
}
|
||||
logrus.Infof("writing MBR")
|
||||
if err := exec.Run(ctx, "dd", fmt.Sprintf("if=%s", s.mbrBin), fmt.Sprintf("of=%s", raw), "bs=440", "count=1", "conv=notrunc"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type syslinuxProvider struct{}
|
||||
|
||||
func (s syslinuxProvider) New(c Config) (Bootloader, error) {
|
||||
mbrBin := ""
|
||||
for _, v := range mbrPaths {
|
||||
if _, err := os.Stat(v); err == nil {
|
||||
mbrBin = v
|
||||
break
|
||||
}
|
||||
}
|
||||
if mbrBin == "" {
|
||||
return nil, fmt.Errorf("unable to find syslinux's mbr.bin path")
|
||||
}
|
||||
return &syslinux{
|
||||
c: c,
|
||||
mbrBin: mbrBin,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s syslinuxProvider) Name() string {
|
||||
return "syslinux"
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterBootloaderProvider(syslinuxProvider{})
|
||||
}
|
Loading…
Reference in New Issue
Block a user