boot.img: simplified generation
This commit is contained in:
parent
d79683b130
commit
c185bc1f7d
@ -1,11 +0,0 @@
|
|||||||
search --no-floppy --set=root --part-label boot --hint $root
|
|
||||||
|
|
||||||
insmod all_video
|
|
||||||
set timeout=3
|
|
||||||
|
|
||||||
set bootdev=PARTNAME=boot
|
|
||||||
|
|
||||||
menuentry "Direktil" {
|
|
||||||
linux /current/vmlinuz direktil.boot=$bootdev
|
|
||||||
initrd /current/initrd
|
|
||||||
}
|
|
BIN
assets/mbr.bin
BIN
assets/mbr.bin
Binary file not shown.
@ -27,7 +27,6 @@ func loadSrc() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("failed to load config from dir: ", err)
|
log.Fatal("failed to load config from dir: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -70,6 +69,11 @@ func main() {
|
|||||||
}
|
}
|
||||||
ips = append(ips, host.IPs...)
|
ips = append(ips, host.IPs...)
|
||||||
|
|
||||||
|
if ctx.Group.Versions["modules"] == "" {
|
||||||
|
// default modules' version to kernel's version
|
||||||
|
ctx.Group.Versions["modules"] = ctx.Group.Kernel
|
||||||
|
}
|
||||||
|
|
||||||
dst.Hosts = append(dst.Hosts, &localconfig.Host{
|
dst.Hosts = append(dst.Hosts, &localconfig.Host{
|
||||||
Name: host.Name,
|
Name: host.Name,
|
||||||
MACs: macs,
|
MACs: macs,
|
||||||
|
@ -22,18 +22,6 @@ func buildBootImg(out io.Writer, ctx *renderContext) (err error) {
|
|||||||
}
|
}
|
||||||
defer rmTempFile(bootImg)
|
defer rmTempFile(bootImg)
|
||||||
|
|
||||||
// 2MB + 2GB + 2MB + 34 sectors
|
|
||||||
bootImg.Truncate(2<<30 + 4<<20 + 34*512)
|
|
||||||
|
|
||||||
// partition
|
|
||||||
err = run("sgdisk",
|
|
||||||
"--new=0:4096:+2G", "--typecode=0:EF00", "-c", "0:boot",
|
|
||||||
"--new=0:0:+2M", "--typecode=0:EF02", "-c", "0:BIOS-BOOT",
|
|
||||||
"--hybrid=1:2", "--print", bootImg.Name())
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = setupBootImage(bootImg, ctx)
|
err = setupBootImage(bootImg, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -68,21 +56,43 @@ func buildBootImgGZ(out io.Writer, ctx *renderContext) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setupBootImage(bootImg *os.File, ctx *renderContext) (err error) {
|
func setupBootImage(bootImg *os.File, ctx *renderContext) (err error) {
|
||||||
|
path, err := ctx.distFetch("grub-support", "1.0.0")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
baseImage, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer baseImage.Close()
|
||||||
|
|
||||||
|
baseImageGz, err := gzip.NewReader(baseImage)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer baseImageGz.Close()
|
||||||
|
_, err = io.Copy(bootImg, baseImageGz)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
devb, err := exec.Command("losetup", "--find", "--show", "--partscan", bootImg.Name()).CombinedOutput()
|
devb, err := exec.Command("losetup", "--find", "--show", "--partscan", bootImg.Name()).CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dev := strings.TrimSpace(string(devb))
|
dev := strings.TrimSpace(string(devb))
|
||||||
defer run("losetup", "-d", dev)
|
defer func() {
|
||||||
|
log.Print("detaching ", dev)
|
||||||
|
run("losetup", "-d", dev)
|
||||||
|
}()
|
||||||
|
|
||||||
log.Print("device: ", dev)
|
log.Print("device: ", dev)
|
||||||
|
|
||||||
err = run("mkfs.vfat", "-n", "DKLBOOT", dev+"p1")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tempDir := bootImg.Name() + ".p1.mount"
|
tempDir := bootImg.Name() + ".p1.mount"
|
||||||
|
|
||||||
err = os.Mkdir(tempDir, 0755)
|
err = os.Mkdir(tempDir, 0755)
|
||||||
@ -91,7 +101,7 @@ func setupBootImage(bootImg *os.File, ctx *renderContext) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
log.Print("Removing ", tempDir)
|
log.Print("removing ", tempDir)
|
||||||
os.RemoveAll(tempDir)
|
os.RemoveAll(tempDir)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -101,16 +111,10 @@ func setupBootImage(bootImg *os.File, ctx *renderContext) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
log.Print("Unmounting ", tempDir)
|
log.Print("unmounting ", tempDir)
|
||||||
syscall.Unmount(tempDir, 0)
|
syscall.Unmount(tempDir, 0)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// setup grub
|
|
||||||
err = run("/scripts/grub_install.sh", bootImg.Name(), dev, tempDir)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// add system elements
|
// add system elements
|
||||||
tarOut, tarIn := io.Pipe()
|
tarOut, tarIn := io.Pipe()
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -1,19 +1,18 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
|
||||||
|
|
||||||
cpio "github.com/cavaliercoder/go-cpio"
|
cpio "github.com/cavaliercoder/go-cpio"
|
||||||
yaml "gopkg.in/yaml.v2"
|
yaml "gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func renderConfig(w http.ResponseWriter, r *http.Request, ctx *renderContext) error {
|
func renderConfig(w http.ResponseWriter, r *http.Request, ctx *renderContext, asJson bool) (err error) {
|
||||||
log.Printf("sending config for %q", ctx.Host.Name)
|
log.Printf("sending config for %q", ctx.Host.Name)
|
||||||
|
|
||||||
_, cfg, err := ctx.Config()
|
_, cfg, err := ctx.Config()
|
||||||
@ -21,14 +20,12 @@ func renderConfig(w http.ResponseWriter, r *http.Request, ctx *renderContext) er
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ba, err := yaml.Marshal(cfg)
|
if asJson {
|
||||||
if err != nil {
|
err = json.NewEncoder(w).Encode(cfg)
|
||||||
return err
|
} else {
|
||||||
|
err = yaml.NewEncoder(w).Encode(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/yaml")
|
|
||||||
http.ServeContent(w, r, "config.yaml", time.Unix(0, 0), bytes.NewReader(ba))
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,9 @@ func (ws *wsHost) register(rws *restful.WebService, alterRB func(*restful.RouteB
|
|||||||
Produces(mime.YAML).
|
Produces(mime.YAML).
|
||||||
Doc("Get the " + ws.hostDoc + "'s configuration"),
|
Doc("Get the " + ws.hostDoc + "'s configuration"),
|
||||||
|
|
||||||
|
b("config.json").
|
||||||
|
Doc("Get the " + ws.hostDoc + "'s configuration (as JSON)"),
|
||||||
|
|
||||||
// metal/local HDD install
|
// metal/local HDD install
|
||||||
b("boot.img").
|
b("boot.img").
|
||||||
Produces(mime.DISK).
|
Produces(mime.DISK).
|
||||||
@ -127,7 +130,10 @@ func renderHost(w http.ResponseWriter, r *http.Request, what string, host *local
|
|||||||
|
|
||||||
switch what {
|
switch what {
|
||||||
case "config":
|
case "config":
|
||||||
err = renderConfig(w, r, ctx)
|
err = renderConfig(w, r, ctx, false)
|
||||||
|
|
||||||
|
case "config.json":
|
||||||
|
err = renderConfig(w, r, ctx, true)
|
||||||
|
|
||||||
case "ipxe":
|
case "ipxe":
|
||||||
err = renderIPXE(w, ctx)
|
err = renderIPXE(w, ctx)
|
||||||
|
@ -1,131 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
disk_image="${1}"
|
|
||||||
LOOP_DEV="${2}"
|
|
||||||
ESP_DIR="${3}"
|
|
||||||
|
|
||||||
# i386-pc or x86_64-efi
|
|
||||||
target=${4:-x86_64-efi}
|
|
||||||
|
|
||||||
export PATH="/opt/grub/bin:/opt/grub/sbin:$PATH"
|
|
||||||
|
|
||||||
info() {
|
|
||||||
echo "INFO:" "$@"
|
|
||||||
}
|
|
||||||
|
|
||||||
warn() {
|
|
||||||
echo "WARN:" "$@"
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup() {
|
|
||||||
if [[ -n "${GRUB_TEMP_DIR}" && -e "${GRUB_TEMP_DIR}" ]]; then
|
|
||||||
rm -r "${GRUB_TEMP_DIR}"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
trap cleanup EXIT
|
|
||||||
|
|
||||||
info "Installing GRUB in ${disk_image##*/}"
|
|
||||||
|
|
||||||
mkdir -p "${ESP_DIR}/grub"
|
|
||||||
GRUB_TEMP_DIR="$(mktemp -d)"
|
|
||||||
|
|
||||||
devmap="${GRUB_TEMP_DIR}/device.map"
|
|
||||||
|
|
||||||
cat >${devmap} <<EOF
|
|
||||||
(hd0) ${LOOP_DEV}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
mkdir -p "${ESP_DIR}/grub"
|
|
||||||
sed -e "s/{{.FSID}}/$ESP_FSID/g" "/assets/grub.cfg" > "${ESP_DIR}/grub/grub.cfg"
|
|
||||||
|
|
||||||
info "Generating grub/load.cfg"
|
|
||||||
# Include a small initial config in the core image to search for the ESP
|
|
||||||
# by filesystem ID in case the platform doesn't provide the boot disk.
|
|
||||||
# The existing $root value is given as a hint so it is searched first.
|
|
||||||
ESP_FSID=$(grub-probe --device-map=$devmap -t fs_uuid -d "${LOOP_DEV}p1")
|
|
||||||
cat > "${ESP_DIR}/grub/load.cfg" <<EOF
|
|
||||||
search.fs_uuid ${ESP_FSID} root \$root
|
|
||||||
set prefix=(memdisk)
|
|
||||||
set
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Generate a memdisk containing the appropriately generated grub.cfg. Doing
|
|
||||||
# this because we need conflicting default behaviors between verity and
|
|
||||||
# non-verity images.
|
|
||||||
info "Generating grub.cfg memdisk"
|
|
||||||
|
|
||||||
sed -e "s/{{.FSID}}/$ESP_FSID/g" "/assets/grub.cfg" > "${GRUB_TEMP_DIR}/grub.cfg"
|
|
||||||
|
|
||||||
mkdir -p "${ESP_DIR}/grub"
|
|
||||||
tar cf "${ESP_DIR}/grub/grub.cfg.tar" \
|
|
||||||
-C "${GRUB_TEMP_DIR}" "grub.cfg"
|
|
||||||
|
|
||||||
for target in i386-pc x86_64-efi
|
|
||||||
do
|
|
||||||
GRUB_SRC="/usr/lib/grub/${target}"
|
|
||||||
GRUB_DIR="grub/${target}"
|
|
||||||
|
|
||||||
[[ -d "${GRUB_SRC}" ]] || die "GRUB not installed at ${GRUB_SRC}"
|
|
||||||
|
|
||||||
info "Compressing modules in ${GRUB_DIR}"
|
|
||||||
mkdir -p "${ESP_DIR}/${GRUB_DIR}"
|
|
||||||
for file in "${GRUB_SRC}"/*{.lst,.mod}; do
|
|
||||||
out="${ESP_DIR}/${GRUB_DIR}/${file##*/}"
|
|
||||||
gzip --best --stdout "${file}" | cat > "${out}"
|
|
||||||
done
|
|
||||||
|
|
||||||
# Modules required to boot a standard configuration
|
|
||||||
CORE_MODULES=( normal search test fat part_gpt search_fs_uuid gzio terminal configfile memdisk tar echo read )
|
|
||||||
#CORE_MODULES+=( search_part_label gptprio )
|
|
||||||
|
|
||||||
# Name of the core image, depends on target
|
|
||||||
CORE_NAME=
|
|
||||||
|
|
||||||
case "${target}" in
|
|
||||||
i386-pc)
|
|
||||||
CORE_MODULES+=( biosdisk serial linux )
|
|
||||||
CORE_NAME="core.img"
|
|
||||||
;;
|
|
||||||
x86_64-efi)
|
|
||||||
CORE_MODULES+=( serial linuxefi efi_gop efinet verify http tftp )
|
|
||||||
#CORE_MODULES+=( getenv smbios )
|
|
||||||
CORE_NAME="core.efi"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
die_notrace "Unknown GRUB target ${target}"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
info "Generating grub/${CORE_NAME}"
|
|
||||||
grub-mkimage \
|
|
||||||
--compression=auto \
|
|
||||||
--format "${target}" \
|
|
||||||
--directory "${GRUB_SRC}" \
|
|
||||||
--config "${ESP_DIR}/grub/load.cfg" \
|
|
||||||
--memdisk "${ESP_DIR}/grub/grub.cfg.tar" \
|
|
||||||
--output "${ESP_DIR}/${GRUB_DIR}/${CORE_NAME}" \
|
|
||||||
"${CORE_MODULES[@]}"
|
|
||||||
done
|
|
||||||
|
|
||||||
# Now target specific steps to make the system bootable
|
|
||||||
info "Installing MBR and the BIOS Boot partition."
|
|
||||||
cp "/usr/lib/grub/i386-pc/boot.img" "${ESP_DIR}/grub/i386-pc"
|
|
||||||
grub-bios-setup --device-map=$devmap \
|
|
||||||
--directory="${ESP_DIR}/grub/i386-pc" "${LOOP_DEV}"
|
|
||||||
|
|
||||||
# backup the MBR
|
|
||||||
dd bs=448 count=1 status=none if="${LOOP_DEV}" \
|
|
||||||
of="${ESP_DIR}/grub/mbr.bin"
|
|
||||||
|
|
||||||
info "Installing default x86_64 UEFI bootloader."
|
|
||||||
mkdir -p "${ESP_DIR}/EFI/boot"
|
|
||||||
|
|
||||||
cp "${ESP_DIR}/grub/x86_64-efi/core.efi" \
|
|
||||||
"${ESP_DIR}/EFI/boot/grubx64.efi"
|
|
||||||
cp "/shim/BOOTX64.EFI" \
|
|
||||||
"${ESP_DIR}/EFI/boot/bootx64.efi"
|
|
||||||
|
|
||||||
cleanup
|
|
||||||
trap - EXIT
|
|
Loading…
Reference in New Issue
Block a user