Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 42 additions & 2 deletions initrd/dockerfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,10 +390,32 @@ func (initrd *dockerfile) Build(ctx context.Context) (string, error) {
"filename": filepath.Base(initrd.dockerfile),
}

// Add the build target if specified (override from command line)
if len(buildTarget) > 0 {
attrs["target"] = buildTarget
} else if initrd.opts.buildTarget != "" {
attrs["target"] = initrd.opts.buildTarget
}

// Add build args from the build config
if initrd.opts.buildArgs != nil {
for k, v := range initrd.opts.buildArgs {
if v == nil {
v, ok := os.LookupEnv(k)
if !ok {
log.G(ctx).
WithField("arg", k).
Warn("could not find build-arg in environment")
continue
}
attrs["build-arg:"+k] = v
} else {
attrs["build-arg:"+k] = *v
}
}
}

// Override build args from the command line
for _, arg := range buildArgs {
k, v, ok := strings.Cut(arg, "=")
if !ok {
Expand All @@ -415,13 +437,31 @@ func (initrd *dockerfile) Build(ctx context.Context) (string, error) {
},
}

fs := make([]secretsprovider.Source, 0, len(buildSecrets))
// Add build secrets from the build config
secretsMap := make(map[string]secretsprovider.Source)
if initrd.opts.buildSecrets != nil {
for _, v := range initrd.opts.buildSecrets {
secretsMap[v.Name] = secretsprovider.Source{
ID: v.Name,
FilePath: v.File,
Env: v.Env,
}
}
}

// Override build secrets from the command line
for _, v := range buildSecrets {
s, err := parseSecret(v)
if err != nil {
return "", err
}
fs = append(fs, *s)
secretsMap[s.ID] = *s
}

// Convert map to slice
fs := make([]secretsprovider.Source, 0, len(secretsMap))
for _, secret := range secretsMap {
fs = append(fs, secret)
}

secretStore, err := secretsprovider.NewStore(fs)
Expand Down
61 changes: 56 additions & 5 deletions initrd/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,21 @@
// You may not use this file except in compliance with the License.
package initrd

type InitrdBuildSecret struct {
Name string
File string
Env string
}

type InitrdOptions struct {
compress bool
output string
cacheDir string
arch string
workdir string
compress bool
output string
cacheDir string
arch string
workdir string
buildArgs map[string]*string
buildTarget string
buildSecrets map[string]InitrdBuildSecret
}

// Whether the resulting CPIO archive file should be compressed.
Expand Down Expand Up @@ -37,6 +46,21 @@ func (opts InitrdOptions) Workdir() string {
return opts.workdir
}

// The build arguments that may be used by certain initrd builders.
func (opts InitrdOptions) BuildArgs() map[string]*string {
return opts.buildArgs
}

// The build target that may be used by certain initrd builders.
func (opts InitrdOptions) BuildTarget() string {
return opts.buildTarget
}

// The build secrets that may be used by certain initrd builders.
func (opts InitrdOptions) BuildSecrets() map[string]InitrdBuildSecret {
return opts.buildSecrets
}

type InitrdOption func(*InitrdOptions) error

// WithCompression sets the compression of the resulting CPIO archive file.
Expand Down Expand Up @@ -86,3 +110,30 @@ func WithWorkdir(dir string) InitrdOption {
return nil
}
}

// WithBuildArgs sets build arguments that may be used by certain initrd
// builders, such as Dockerfile-based ones.
func WithBuildArgs(args map[string]*string) InitrdOption {
return func(opts *InitrdOptions) error {
opts.buildArgs = args
return nil
}
}

// WithBuildTarget sets the build target that may be used by certain initrd
// builders, such as Dockerfile-based ones.
func WithBuildTarget(target string) InitrdOption {
return func(opts *InitrdOptions) error {
opts.buildTarget = target
return nil
}
}

// WithBuildSecrets sets build secrets that may be used by certain initrd
// builders, such as Dockerfile-based ones.
func WithBuildSecrets(secrets map[string]InitrdBuildSecret) InitrdOption {
return func(opts *InitrdOptions) error {
opts.buildSecrets = secrets
return nil
}
}
22 changes: 10 additions & 12 deletions internal/cli/kraft/utils/rootfs.go → initrd/rootfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,22 @@
// Licensed under the BSD-3-Clause License (the "License").
// You may not use this file except in compliance with the License.

package utils
package initrd

import (
"context"
"fmt"
"path/filepath"

"kraftkit.sh/config"
"kraftkit.sh/initrd"
"kraftkit.sh/log"
"kraftkit.sh/tui/processtree"
"kraftkit.sh/unikraft"
)

// BuildRootfs generates a rootfs based on the provided working directory and
// the rootfs entrypoint for the provided target(s).
func BuildRootfs(ctx context.Context, workdir, rootfs string, compress bool, arch string) (initrd.Initrd, []string, []string, error) {
func BuildRootfs(ctx context.Context, workdir, rootfs string, compress bool, arch string, initrdOptions []InitrdOption) (Initrd, []string, []string, error) {
Copy link
Member

@nderjung nderjung Oct 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's turn the prototype into an options pattern:

- func BuildRootfs(ctx context.Context, workdir, rootfs string, compress bool, arch string, initrdOptions []InitrdOption) (Initrd, []string, []string, error) {
+ func BuildRootfs(ctx context.Context, opts ...InitrdOption) (Initrd, []string, []string, error) {

Later:

var bopts InitrdOoptions
for _, opt := range opts {
  if err := opt(&bopts); err != nil {
     return nil, nil, nil, err
  }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with these changes the processing of paths is moved to the callers, do you want me to move it inside WithOutput and WithCacheDir?

if rootfs == "" {
return nil, nil, nil, nil
}
Expand All @@ -28,22 +27,21 @@ func BuildRootfs(ctx context.Context, workdir, rootfs string, compress bool, arc
var cmds []string
var envs []string

ramfs, err := initrd.New(ctx,
rootfs,
initrd.WithWorkdir(workdir),
initrd.WithOutput(filepath.Join(
ramfs, err := New(ctx, rootfs, append(initrdOptions,
WithWorkdir(workdir),
WithOutput(filepath.Join(
workdir,
unikraft.BuildDir,
fmt.Sprintf(initrd.DefaultInitramfsArchFileName, arch),
fmt.Sprintf(DefaultInitramfsArchFileName, arch),
)),
initrd.WithCacheDir(filepath.Join(
WithCacheDir(filepath.Join(
workdir,
unikraft.VendorDir,
"rootfs-cache",
)),
initrd.WithArchitecture(arch),
initrd.WithCompression(compress),
)
WithArchitecture(arch),
WithCompression(compress),
)...)
if err != nil {
return nil, nil, nil, fmt.Errorf("could not initialize initramfs builder: %w", err)
}
Expand Down
51 changes: 26 additions & 25 deletions internal/cli/kraft/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
"github.com/spf13/cobra"

"kraftkit.sh/cmdfactory"
"kraftkit.sh/internal/cli/kraft/utils"
"kraftkit.sh/initrd"
"kraftkit.sh/internal/fancymap"
"kraftkit.sh/iostreams"
"kraftkit.sh/tui"
Expand All @@ -32,29 +32,30 @@ import (
var ErrContextNotBuildable = fmt.Errorf("could not determine what or how to build from the given context")

type BuildOptions struct {
All bool `long:"all" usage:"Build all targets"`
Architecture string `long:"arch" short:"m" usage:"Filter the creation of the build by architecture of known targets (x86_64/arm64/arm)"`
DotConfig string `long:"config" short:"c" usage:"Override the path to the KConfig .config file"`
Env []string `long:"env" short:"e" usage:"Set environment variables to be built in the unikernel" split:"false"`
ForcePull bool `long:"force-pull" usage:"Force pulling packages before building"`
Jobs int `long:"jobs" short:"j" usage:"Allow N jobs at once"`
KernelDbg bool `long:"dbg" usage:"Build the debuggable (symbolic) kernel image instead of the stripped image"`
Kraftfile string `long:"kraftfile" short:"K" usage:"Set an alternative path of the Kraftfile"`
NoCache bool `long:"no-cache" short:"F" usage:"Force a rebuild even if existing intermediate artifacts already exist"`
NoConfigure bool `long:"no-configure" usage:"Do not run Unikraft's configure step before building"`
NoFast bool `long:"no-fast" usage:"Do not use maximum parallelization when performing the build"`
NoFetch bool `long:"no-fetch" usage:"Do not run Unikraft's fetch step before building"`
NoRootfs bool `long:"no-rootfs" usage:"Do not build the root file system (initramfs)"`
NoUpdate bool `long:"no-update" usage:"Do not update package index before running the build"`
Output string `long:"output" short:"o" usage:"Set the output directory for the build artifacts"`
Platform string `long:"plat" short:"p" usage:"Filter the creation of the build by platform of known targets (fc/qemu/xen)"`
PrintStats bool `long:"print-stats" usage:"Print build statistics"`
Project app.Application `noattribute:"true"`
Rootfs string `long:"rootfs" usage:"Specify a path to use as root file system (can be volume or initramfs)"`
SaveBuildLog string `long:"build-log" usage:"Use the specified file to save the output from the build"`
Target *target.Target `noattribute:"true"`
TargetName string `long:"target" short:"t" usage:"Build a particular known target"`
Workdir string `noattribute:"true"`
All bool `long:"all" usage:"Build all targets"`
Architecture string `long:"arch" short:"m" usage:"Filter the creation of the build by architecture of known targets (x86_64/arm64/arm)"`
InitrdOptions []initrd.InitrdOption `noattribute:"true"`
DotConfig string `long:"config" short:"c" usage:"Override the path to the KConfig .config file"`
Env []string `long:"env" short:"e" usage:"Set environment variables to be built in the unikernel" split:"false"`
ForcePull bool `long:"force-pull" usage:"Force pulling packages before building"`
Jobs int `long:"jobs" short:"j" usage:"Allow N jobs at once"`
KernelDbg bool `long:"dbg" usage:"Build the debuggable (symbolic) kernel image instead of the stripped image"`
Kraftfile string `long:"kraftfile" short:"K" usage:"Set an alternative path of the Kraftfile"`
NoCache bool `long:"no-cache" short:"F" usage:"Force a rebuild even if existing intermediate artifacts already exist"`
NoConfigure bool `long:"no-configure" usage:"Do not run Unikraft's configure step before building"`
NoFast bool `long:"no-fast" usage:"Do not use maximum parallelization when performing the build"`
NoFetch bool `long:"no-fetch" usage:"Do not run Unikraft's fetch step before building"`
NoRootfs bool `long:"no-rootfs" usage:"Do not build the root file system (initramfs)"`
NoUpdate bool `long:"no-update" usage:"Do not update package index before running the build"`
Output string `long:"output" short:"o" usage:"Set the output directory for the build artifacts"`
Platform string `long:"plat" short:"p" usage:"Filter the creation of the build by platform of known targets (fc/qemu/xen)"`
PrintStats bool `long:"print-stats" usage:"Print build statistics"`
Project app.Application `noattribute:"true"`
Rootfs string `long:"rootfs" usage:"Specify a path to use as root file system (can be volume or initramfs)"`
SaveBuildLog string `long:"build-log" usage:"Use the specified file to save the output from the build"`
Target *target.Target `noattribute:"true"`
TargetName string `long:"target" short:"t" usage:"Build a particular known target"`
Workdir string `noattribute:"true"`

statistics map[string]string
}
Expand Down Expand Up @@ -108,7 +109,7 @@ func Build(ctx context.Context, opts *BuildOptions, args ...string) error {
return fmt.Errorf("could not complete build: %w", err)
}

if _, _, _, err = utils.BuildRootfs(ctx, opts.Workdir, opts.Rootfs, false, (*opts.Target).Architecture().String()); err != nil {
if _, _, _, err = initrd.BuildRootfs(ctx, opts.Workdir, opts.Rootfs, false, (*opts.Target).Architecture().String(), opts.InitrdOptions); err != nil {
return err
}

Expand Down
21 changes: 21 additions & 0 deletions internal/cli/kraft/cloud/compose/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"kraftkit.sh/cmdfactory"
"kraftkit.sh/compose"
"kraftkit.sh/config"
"kraftkit.sh/initrd"
"kraftkit.sh/internal/cli/kraft/build"
"kraftkit.sh/internal/cli/kraft/cloud/utils"
"kraftkit.sh/internal/cli/kraft/pkg"
Expand Down Expand Up @@ -256,6 +257,26 @@ func Build(ctx context.Context, opts *BuildOptions, args ...string) error {
popts.Rootfs = rootfs
}

initrdOptions := []initrd.InitrdOption{
initrd.WithBuildArgs(service.Build.Args),
initrd.WithBuildTarget(service.Build.Target),
}
secrets := map[string]initrd.InitrdBuildSecret{}
for _, secretRef := range service.Build.Secrets {
if secret, ok := opts.Project.Secrets[secretRef.Source]; ok {
secrets[secretRef.Source] = initrd.InitrdBuildSecret{
Name: secret.Name,
File: secret.File,
Env: secret.Environment,
}
}
}
if len(secrets) > 0 {
initrdOptions = append(initrdOptions, initrd.WithBuildSecrets(secrets))
}

bopts.InitrdOptions = initrdOptions
popts.InitrdOptions = initrdOptions
bopts.Workdir = service.Build.Context
popts.Workdir = service.Build.Context
bopts.Project = project
Expand Down
3 changes: 1 addition & 2 deletions internal/cli/kraft/pkg/packager_cli_kernel.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (

"kraftkit.sh/config"
"kraftkit.sh/initrd"
"kraftkit.sh/internal/cli/kraft/utils"
"kraftkit.sh/log"
"kraftkit.sh/pack"
"kraftkit.sh/packmanager"
Expand Down Expand Up @@ -66,7 +65,7 @@ func (p *packagerCliKernel) Pack(ctx context.Context, opts *PkgOptions, args ...
var cmds []string
var envs []string
var rootfs initrd.Initrd
if rootfs, cmds, envs, err = utils.BuildRootfs(ctx, opts.Workdir, opts.Rootfs, opts.Compress, targ.Architecture().String()); err != nil {
if rootfs, cmds, envs, err = initrd.BuildRootfs(ctx, opts.Workdir, opts.Rootfs, opts.Compress, targ.Architecture().String(), opts.InitrdOptions); err != nil {
return nil, fmt.Errorf("could not build rootfs: %w", err)
}

Expand Down
2 changes: 1 addition & 1 deletion internal/cli/kraft/pkg/packager_kraftfile_runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ func (p *packagerKraftfileRuntime) Pack(ctx context.Context, opts *PkgOptions, a
}

var rootfsArgs []string
if p.rootfs, rootfsArgs, p.env, err = utils.BuildRootfs(ctx, opts.Workdir, opts.Rootfs, opts.Compress, p.architecture.String()); err != nil {
if p.rootfs, rootfsArgs, p.env, err = initrd.BuildRootfs(ctx, opts.Workdir, opts.Rootfs, opts.Compress, p.architecture.String(), opts.InitrdOptions); err != nil {
return nil, fmt.Errorf("could not build rootfs: %w", err)
}

Expand Down
3 changes: 1 addition & 2 deletions internal/cli/kraft/pkg/packager_kraftfile_unikraft.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"github.com/mattn/go-shellwords"
"kraftkit.sh/config"
"kraftkit.sh/initrd"
"kraftkit.sh/internal/cli/kraft/utils"
"kraftkit.sh/log"
"kraftkit.sh/pack"
"kraftkit.sh/packmanager"
Expand Down Expand Up @@ -108,7 +107,7 @@ func (p *packagerKraftfileUnikraft) Pack(ctx context.Context, opts *PkgOptions,
"CONFIG_LIBPOSIX_VFS_FSTAB_BUILTIN_EINITRD",
"CONFIG_LIBPOSIX_VFS_FSTAB_FALLBACK_EINITRD",
) {
if rootfs, cmds, envs, err = utils.BuildRootfs(ctx, opts.Workdir, opts.Rootfs, opts.Compress, targ.Architecture().String()); err != nil {
if rootfs, cmds, envs, err = initrd.BuildRootfs(ctx, opts.Workdir, opts.Rootfs, opts.Compress, targ.Architecture().String(), opts.InitrdOptions); err != nil {
return nil, fmt.Errorf("could not build rootfs: %w", err)
}
}
Expand Down
Loading