Skip to content

Commit

Permalink
[WIP] Import the build-uki command from enki
Browse files Browse the repository at this point in the history
As part of kairos-io/kairos#1633

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
  • Loading branch information
jimmykarily committed Nov 1, 2024
1 parent 6533f98 commit fa7a4aa
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 2 deletions.
13 changes: 12 additions & 1 deletion internal/cmd/app.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package cmd

import (
"errors"
"os"

"github.com/kairos-io/AuroraBoot/deployer"
"github.com/kairos-io/AuroraBoot/internal"
sdkTypes "github.com/kairos-io/kairos-sdk/types"
Expand All @@ -14,7 +17,7 @@ func GetApp(version string) *cli.App {
Version: version,
Authors: []*cli.Author{{Name: "Kairos authors", Email: "members@kairos.io"}},
Usage: "auroraboot",
Commands: []*cli.Command{&BuildISOCmd},
Commands: []*cli.Command{&BuildISOCmd, &BuildUKICmd},
Flags: []cli.Flag{
&cli.StringSliceFlag{
Name: "set",
Expand Down Expand Up @@ -56,3 +59,11 @@ func GetApp(version string) *cli.App {
},
}
}

// CheckRoot is a helper which can add it to commands that require root
func CheckRoot() error {
if os.Geteuid() != 0 {
return errors.New("this command requires root privileges")
}
return nil
}
2 changes: 1 addition & 1 deletion internal/cmd/build-iso.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const (

var BuildISOCmd = cli.Command{
Name: "build-iso",
Aliases: []string{"b"},
Aliases: []string{"bi"},
Usage: "Builds an ISO from a container image or github release",
Flags: []cli.Flag{
&cli.StringFlag{
Expand Down
157 changes: 157 additions & 0 deletions internal/cmd/build-uki.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package cmd

import (
"fmt"
"os"
"path/filepath"
"strings"

"github.com/kairos-io/enki/pkg/constants"
enkiconstants "github.com/kairos-io/enki/pkg/constants"
"github.com/spf13/viper"
"github.com/urfave/cli/v2"
)

// Use: "build-uki SourceImage",
// Short: "Build a UKI artifact from a container image",
var BuildUKICmd = cli.Command{
Name: "build-uki",
Aliases: []string{"bu"},
Usage: "Builds a UKI artifact from a container image",
ArgsUsage: "<source>",
Description: "Build a UKI artifact from a container image\n\n" +
"SourceImage - should be provided as uri in following format <sourceType>:<sourceName>\n" +
" * <sourceType> - might be [\"dir\", \"file\", \"oci\", \"docker\"], as default is \"docker\"\n" +
" * <sourceName> - is path to file or directory, image name with tag version\n" +
"The following files are expected inside the keys directory:\n" +
" - DB.crt\n" +
" - DB.der\n" +
" - DB.key\n" +
" - DB.auth\n" +
" - KEK.der\n" +
" - KEK.auth\n" +
" - PK.der\n" +
" - PK.auth\n" +
" - tpm2-pcr-private.pem\n",
Before: func(ctx *cli.Context) error {
artifact := ctx.String("output-type")
if artifact != string(constants.DefaultOutput) && artifact != string(constants.IsoOutput) && artifact != string(constants.ContainerOutput) {
return fmt.Errorf("invalid output type: %s", artifact)
}

overlayRootfs := ctx.String("overlay-rootfs")
if overlayRootfs != "" {
// Check if overlay dir exists by doing an os.stat
// If it does not exist, return an error
ol, err := os.Stat(overlayRootfs)
if err != nil {
return fmt.Errorf("overlay-rootfs directory does not exist: %s", overlayRootfs)
}
if !ol.IsDir() {
return fmt.Errorf("overlay-rootfs is not a directory: %s", overlayRootfs)
}

// Transform it into absolute path
absolutePath, err := filepath.Abs(overlayRootfs)
if err != nil {
viper.Set("overlay-rootfs", absolutePath)
}
}
overlayIso := ctx.String("overlay-iso")
if overlayIso != "" {
// Check if overlay dir exists by doing an os.stat
// If it does not exist, return an error
ol, err := os.Stat(overlayIso)
if err != nil {
return fmt.Errorf("overlay directory does not exist: %s", overlayIso)
}
if !ol.IsDir() {
return fmt.Errorf("overlay is not a directory: %s", overlayIso)
}

// Check if we are setting a different artifact and overlay-iso is set
if artifact != string(constants.IsoOutput) {
return fmt.Errorf("overlay-iso is only supported for iso artifacts")
}

// Transform it into absolute path
absolutePath, err := filepath.Abs(overlayIso)
if err != nil {
viper.Set("overlay-iso", absolutePath)
}
}

// Check if the keys directory exists
keysDir := ctx.String("keys")
_, err := os.Stat(keysDir)
if err != nil {
return fmt.Errorf("keys directory does not exist: %s", keysDir)
}
// Check if the keys directory contains the required files
requiredFiles := []string{"db.der", "db.key", "db.auth", "KEK.der", "KEK.auth", "PK.der", "PK.auth", "tpm2-pcr-private.pem"}
for _, file := range requiredFiles {
_, err = os.Stat(filepath.Join(keysDir, file))
if err != nil {
return fmt.Errorf("keys directory does not contain required file: %s", file)
}
}
return CheckRoot()
},
Flags: []cli.Flag{
&cli.StringFlag{
Name: "name",
Aliases: []string{"n"},
Usage: "Basename of the generated artifact (ignored for uki output type)",
},
&cli.StringFlag{
Name: "output-dir",
Aliases: []string{"d"},
Value: ".",
Usage: "Output dir for artifact",
},
&cli.StringFlag{
Name: "output-type",
Aliases: []string{"t"},
Value: string(enkiconstants.DefaultOutput),
Usage: fmt.Sprintf("Artifact output type [%s]", strings.Join(enkiconstants.OutPutTypes(), ", ")),
},
&cli.StringFlag{
Name: "overlay-rootfs",
Aliases: []string{"o"},
Usage: "Dir with files to be applied to the system rootfs.\nAll the files under this dir will be copied into the rootfs of the uki respecting the directory structure under the dir.",
},
&cli.StringFlag{
Name: "overlay-iso",
Aliases: []string{"i"},
Usage: "Dir with files to be copied to the ISO rootfs.",
},
&cli.StringFlag{
Name: "boot-branding",
Value: "Kairos",
Usage: "Boot title branding",
},
&cli.BoolFlag{
Name: "include-version-in-config",
Value: false,
Usage: "Include the OS version in the .config file",
},
&cli.BoolFlag{
Name: "include-cmdline-in-config",
Value: false,
Usage: "Include the cmdline in the .config file. Only the extra values are included.",
},
// c.Flags().StringSliceP("extra-cmdline", "c", []string{}, "Add extra efi files with this cmdline for the default 'norole' artifacts. This creates efi files with the default cmdline and extra efi files with the default+provided cmdline.")
// c.Flags().StringP("extend-cmdline", "x", "", "Extend the default cmdline for the default 'norole' artifacts. This creates efi files with the default+provided cmdline.")
// c.Flags().StringSliceP("single-efi-cmdline", "s", []string{}, "Add one extra efi file with the default+provided cmdline. The syntax is '--single-efi-cmdline \"My Entry: cmdline,options,here\"'. The boot entry name is the text under which it appears in systemd-boot menu.")
// c.Flags().StringP("keys", "k", "", "Directory with the signing keys")
// c.Flags().StringP("default-entry", "e", "", "Default entry selected in the boot menu.\nSupported glob wildcard patterns are \"?\", \"*\", and \"[...]\".\nIf not selected, the default entry with install-mode is selected.")
// c.Flags().Int64P("efi-size-warn", "", 1024, "EFI file size warning threshold in megabytes. Default is 1024.")
// c.Flags().String("secure-boot-enroll", "if-safe", "The value of secure-boot-enroll option of systemd-boot. Possible values: off|manual|if-safe|force. Minimum systemd version: 253. Docs: https://manpages.debian.org/experimental/systemd-boot/loader.conf.5.en.html. !! Danger: this feature might soft-brick your device if used improperly !!")
// c.Flags().StringP("splash", "", "", "Path to the custom logo splash BMP file.")

// c.MarkFlagRequired("keys")
// // Mark some flags as mutually exclusive
// c.MarkFlagsMutuallyExclusive([]string{"extra-cmdline", "extend-cmdline"}...)

},
}

0 comments on commit fa7a4aa

Please sign in to comment.