Skip to content

Commit bc1757c

Browse files
authored
feat: add extra command line support for boot entries (#373)
1 parent 1972cf8 commit bc1757c

File tree

6 files changed

+80
-26
lines changed

6 files changed

+80
-26
lines changed

Dockerfile

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ RUN dnf -y update
2525
RUN dnf -y install dnf-plugins-core && dnf-3 config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
2626
## ISO+ Arm image + Netboot + cloud images Build depedencies
2727
# opensc is needed for the pkcs11 module to work
28+
# llvm is needed for uki building specifically llvm-objcopy
2829
RUN dnf in -y bc \
2930
binutils \
3031
containerd.io \
@@ -41,6 +42,7 @@ RUN dnf in -y bc \
4142
jq \
4243
kpartx \
4344
lvm2 \
45+
llvm \
4446
mtools \
4547
openssl \
4648
opensc \
@@ -117,10 +119,6 @@ RUN luet install --config /tmp/luet-arm64.yaml -y static/grub-artifacts --system
117119
# You can build amd64 raw images for alpine so....we need this in both images
118120
RUN luet install --config /tmp/luet-amd64.yaml -y static/grub-artifacts --system-target /amd/raw/grubartifacts
119121

120-
# kairos-agent so we can use the pull-image
121-
# TODO: What? I cant see where this is used anywhere? Check why its here? Its like 35Mb on nothingness if not used?
122-
RUN luet install -y system/kairos-agent
123-
124122
# remove luet tmp files. Side effect of setting the system-target is that it treats it as a root fs
125123
# so temporal files are stored in each dir
126124
RUN rm -Rf /arm/systemd-boot/var/tmp

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ require (
1616
github.com/google/go-containerregistry v0.20.6
1717
github.com/hashicorp/go-multierror v1.1.1
1818
github.com/joho/godotenv v1.5.1
19-
github.com/kairos-io/go-ukify v0.3.1
19+
github.com/kairos-io/go-ukify v0.4.0
2020
github.com/kairos-io/kairos-agent/v2 v2.24.2
2121
github.com/kairos-io/kairos-sdk v0.10.0
2222
github.com/kairos-io/netboot v0.0.0-20250707091041-e289e132c0ba

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -647,8 +647,8 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
647647
github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk=
648648
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
649649
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
650-
github.com/kairos-io/go-ukify v0.3.1 h1:ta+QtChSmQiVh0A8OFz0V/2anrnjXwjWPxASRjgQ1s8=
651-
github.com/kairos-io/go-ukify v0.3.1/go.mod h1:zdyO9+A4is8kaJ75A+7mfZdvQifLyxc+FPg3j8WzR+U=
650+
github.com/kairos-io/go-ukify v0.4.0 h1:Iop44nIvPMCygw3W/Ji3VdEZAcpXMc17wFtJWIVr4wg=
651+
github.com/kairos-io/go-ukify v0.4.0/go.mod h1:zdyO9+A4is8kaJ75A+7mfZdvQifLyxc+FPg3j8WzR+U=
652652
github.com/kairos-io/kairos-agent/v2 v2.24.2 h1:uLKTFQvT7S+CaNM6cIYxmVtCA5VPAuCQCRxyv38HAhE=
653653
github.com/kairos-io/kairos-agent/v2 v2.24.2/go.mod h1:BHjKF9+kxWccaCJcfh628y6Aky7rfnXfys+V6A8fugo=
654654
github.com/kairos-io/kairos-sdk v0.10.0 h1:QT4yBP6ZLjmrn3zJ2lrJheI68vRg6MyRbq57lx8Z3JQ=

image-assets/luet-amd64.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ repositories:
1313
urls:
1414
- "quay.io/kairos/packages"
1515
# renovate: datasource=docker depName=quay.io/kairos/packages
16-
reference: 202504300949-git421ee1de-repository.yaml
16+
reference: 202509262041-gitc24d0fc0-repository.yaml

image-assets/luet-arm64.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ repositories:
1313
urls:
1414
- "quay.io/kairos/packages-arm64"
1515
# renovate: datasource=docker depName=quay.io/kairos/packages-arm64
16-
reference: 202504300946-git421ee1de-repository.yaml
16+
reference: 202509262042-gitc24d0fc0-repository.yaml

internal/cmd/build-uki.go

Lines changed: 73 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"strings"
1515

1616
"github.com/kairos-io/AuroraBoot/internal"
17-
1817
"github.com/kairos-io/AuroraBoot/pkg/constants"
1918
"github.com/kairos-io/AuroraBoot/pkg/ops"
2019
"github.com/kairos-io/AuroraBoot/pkg/utils"
@@ -141,6 +140,11 @@ var BuildUKICmd = cli.Command{
141140
Name: "splash",
142141
Usage: "Path to the custom logo splash BMP file.",
143142
},
143+
&cli.BoolFlag{
144+
Name: "cmd-lines-v2",
145+
Value: false,
146+
Usage: "Use the new cmdline v2 format to generate a multiprofile efi with all the extra cmdlines. This requires systemd-boot 257 or newer.",
147+
},
144148
},
145149
Before: func(ctx *cli.Context) error {
146150
// // Mark flags as mutually exclusive
@@ -327,9 +331,10 @@ var BuildUKICmd = cli.Command{
327331
boodBranding := ctx.String("boot-branding")
328332
extraCmdlines := ctx.StringSlice("extra-cmdline")
329333
singleEfiCmdlines := ctx.StringSlice("single-efi-cmdline")
334+
cmdLinesV2 := ctx.Bool("cmd-lines-v2")
330335

331336
entries := append(
332-
GetUkiCmdline(extendCmdline, boodBranding, extraCmdlines),
337+
GetUkiCmdline(extendCmdline, boodBranding, extraCmdlines, cmdLinesV2),
333338
GetUkiSingleCmdlines(boodBranding, singleEfiCmdlines, logger)...)
334339

335340
for _, entry := range entries {
@@ -376,6 +381,17 @@ var BuildUKICmd = cli.Command{
376381
Splash: ctx.String("splash"),
377382
}
378383

384+
// If we are using cmdLinesV2 we need to pass the extra cmdlines to generate a multiprofile efi
385+
if cmdLinesV2 {
386+
// extra cmdlines expand the base one, not substitute it completely
387+
// so we need to expand the entry.Cmdline with the extra cmdlines
388+
389+
for _, cmd := range extraCmdlines {
390+
slog.Debug("Expanding extra cmdline with base", "cmdline", cmd, "base", entry.Cmdline)
391+
builder.ExtraCmdlines = append(builder.ExtraCmdlines, fmt.Sprintf("%s %s", entry.Cmdline, cmd))
392+
}
393+
}
394+
379395
if err := os.Chdir(sourceDir); err != nil {
380396
return fmt.Errorf("changing to %s directory: %w", sourceDir, err)
381397
}
@@ -385,9 +401,27 @@ var BuildUKICmd = cli.Command{
385401
}
386402

387403
logger.Info("Creating kairos and loader conf files")
388-
if err := createConfFiles(sourceDir, entry.Cmdline, entry.Title, entry.FileName, kairosVersion, ctx.Bool("include-version-in-config"), ctx.Bool("include-cmdline-in-config")); err != nil {
404+
405+
// Always create the base config with profile 0
406+
logger.Info("Creating base config file with profile 0")
407+
if err := createConfFiles(sourceDir, entry.Cmdline, entry.Title, entry.FileName, kairosVersion, "0", ctx.Bool("include-version-in-config"), ctx.Bool("include-cmdline-in-config")); err != nil {
389408
return err
390409
}
410+
// If cmdLinesV2 is set, we need to create the extra config files with the corresponding profile number
411+
// Profile number is the index + 1 (0 is the base config)
412+
if cmdLinesV2 {
413+
for i, cmd := range extraCmdlines {
414+
logger.Info("Creating extra config file for cmdline", "cmdline", cmd)
415+
profile := fmt.Sprintf("%d", i+1)
416+
// I hoped that we should not set this and systemd-boot would automatically get it from the .profile section
417+
// as that can include the ID and title, but seems like it doesnt in neither type 1 or 2 entries :(
418+
title := fmt.Sprintf("%s (%s)", entry.Title, cmd)
419+
420+
if err := createConfFiles(sourceDir, fmt.Sprintf("%s %s", entry.Cmdline, cmd), title, entry.FileName, kairosVersion, profile, ctx.Bool("include-version-in-config"), ctx.Bool("include-cmdline-in-config")); err != nil {
421+
return err
422+
}
423+
}
424+
}
391425
}
392426

393427
if err := createSystemdConf(sourceDir, ctx.String("default-entry"), ctx.String("secure-boot-enroll")); err != nil {
@@ -676,7 +710,13 @@ func getEfiStub(arch string) (string, error) {
676710
}
677711
}
678712

679-
func createConfFiles(sourceDir, cmdline, title, finalEfiName, version string, includeVersion, includeCmdline bool) error {
713+
func createConfFiles(sourceDir, cmdline, title, finalEfiName, version, profile string, includeVersion, includeCmdline bool) error {
714+
if _, err := os.Stat(filepath.Join(sourceDir, "entries")); os.IsNotExist(err) {
715+
if err := os.Mkdir(filepath.Join(sourceDir, "entries"), os.ModePerm); err != nil {
716+
return fmt.Errorf("error creating entries directory: %w", err)
717+
}
718+
}
719+
680720
// This is stored in the config
681721
var extraCmdline string
682722
// For the config title we get only the extra cmdline we added, no replacement of spaces with underscores needed
@@ -688,8 +728,7 @@ func createConfFiles(sourceDir, cmdline, title, finalEfiName, version string, in
688728

689729
// You can add entries into the config files, they will be ignored by systemd-boot
690730
// So we store the cmdline in a key cmdline for easy tracking of what was added to the uki cmdline
691-
692-
configData := fmt.Sprintf("title %s\nefi /EFI/kairos/%s.efi\n", title, finalEfiName)
731+
configData := fmt.Sprintf("title %s\nsort-key %s-%s\nefi /EFI/kairos/%s.efi\nprofile %s\n", title, finalEfiName, profile, finalEfiName, profile)
693732

694733
if includeVersion {
695734
configData = fmt.Sprintf("%sversion %s\n", configData, version)
@@ -699,7 +738,13 @@ func createConfFiles(sourceDir, cmdline, title, finalEfiName, version string, in
699738
configData = fmt.Sprintf("%scmdline %s\n", configData, strings.Trim(extraCmdline, " "))
700739
}
701740

702-
err := os.WriteFile(filepath.Join(sourceDir, finalEfiName+".conf"), []byte(configData), os.ModePerm)
741+
confName := finalEfiName + ".conf"
742+
743+
if profile != "0" {
744+
// For profiles different than 0 we add the profile number to the conf name so we can have multiple confs for the same efi
745+
confName = fmt.Sprintf("%s-profile%s.conf", finalEfiName, profile)
746+
}
747+
err := os.WriteFile(filepath.Join(sourceDir, "entries", confName), []byte(configData), os.ModePerm)
703748
if err != nil {
704749
return fmt.Errorf("creating the %s.conf file", finalEfiName)
705750
}
@@ -826,7 +871,16 @@ func imageFiles(sourceDir, keysDir string, entries []utils.BootEntry) (map[strin
826871
// Add the kairos efi files and the loader conf files for each cmdline
827872
for _, entry := range entries {
828873
data["EFI/kairos"] = append(data["EFI/kairos"], filepath.Join(sourceDir, entry.FileName+".efi"))
829-
data["loader/entries"] = append(data["loader/entries"], filepath.Join(sourceDir, entry.FileName+".conf"))
874+
}
875+
// add any conf files that are in the sourceDir+entries dir
876+
files, err := os.ReadDir(filepath.Join(sourceDir, "entries"))
877+
if err != nil {
878+
return data, fmt.Errorf("reading source dir: %w", err)
879+
}
880+
for _, f := range files {
881+
if strings.HasSuffix(f.Name(), ".conf") {
882+
data["loader/entries"] = append(data["loader/entries"], filepath.Join(sourceDir, "entries", f.Name()))
883+
}
830884
}
831885
return data, nil
832886
}
@@ -983,7 +1037,7 @@ func createContainer(sourceDir, outputDir, artifactName, outputName string, logg
9831037
// For each cmdline passed, we generate a uki file with that cmdline
9841038
// extend-cmdline will just extend the default cmdline so we only create one efi file. Artifact name is the default one
9851039
// extra-cmdline will create a new efi file for each cmdline passed. artifact name is generated from the cmdline
986-
func GetUkiCmdline(cmdlineExtend, bootBranding string, extraCmdlines []string) []utils.BootEntry {
1040+
func GetUkiCmdline(cmdlineExtend, bootBranding string, extraCmdlines []string, cmdLinesV2 bool) []utils.BootEntry {
9871041
defaultCmdLine := constants.UkiCmdline + " " + constants.UkiCmdlineInstall
9881042

9891043
// Override the default cmdline if the user passed one
@@ -1002,14 +1056,16 @@ func GetUkiCmdline(cmdlineExtend, bootBranding string, extraCmdlines []string) [
10021056
FileName: constants.ArtifactBaseName,
10031057
}}
10041058

1005-
// extra
1006-
for _, extra := range extraCmdlines {
1007-
cmdline := defaultCmdLine + " " + extra
1008-
result = append(result, utils.BootEntry{
1009-
Cmdline: cmdline,
1010-
Title: bootBranding,
1011-
FileName: NameFromCmdline(constants.ArtifactBaseName, cmdline),
1012-
})
1059+
// if we are using the old style cmdlines, we add the extra ones
1060+
if !cmdLinesV2 {
1061+
for _, extra := range extraCmdlines {
1062+
cmdline := defaultCmdLine + " " + extra
1063+
result = append(result, utils.BootEntry{
1064+
Cmdline: cmdline,
1065+
Title: bootBranding,
1066+
FileName: NameFromCmdline(constants.ArtifactBaseName, cmdline),
1067+
})
1068+
}
10131069
}
10141070

10151071
return result

0 commit comments

Comments
 (0)