Skip to content

Commit 45b71b8

Browse files
authored
feat: Use explicit kraftfile type if specified (#290)
Reviewed-by: Cezar Craciunoiu <cezar.craciunoiu@unikraft.com> Approved-by: Cezar Craciunoiu <cezar.craciunoiu@unikraft.com>
2 parents b72ba9f + ab4b9e7 commit 45b71b8

9 files changed

Lines changed: 578 additions & 50 deletions

File tree

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ require (
5151
unikraft.com/x/image-spec v0.0.0-20260402110633-a9f8f467a2b5
5252
unikraft.com/x/joinerrgroup v0.0.0-20260304162956-523940cab1de
5353
unikraft.com/x/kingkong v0.0.0-20260331102539-2c733927b46f
54-
unikraft.com/x/kraftfile v0.0.0-20260318103446-c2c548a69fc0
54+
unikraft.com/x/kraftfile v0.0.0-20260422155551-dcd071f425c2
5555
unikraft.com/x/log v0.0.0-20260126171022-af62c17fcdf7
5656
unikraft.com/x/ptr v0.0.0-20260126094137-ab6e717e5679
5757
)

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -511,8 +511,8 @@ unikraft.com/x/joinerrgroup v0.0.0-20260304162956-523940cab1de h1:cm4FnPvnahRIK0
511511
unikraft.com/x/joinerrgroup v0.0.0-20260304162956-523940cab1de/go.mod h1:XND1VvLxwqKFGrmdwUTWps4WEpMm7HTHPQg9HWQtrxg=
512512
unikraft.com/x/kingkong v0.0.0-20260331102539-2c733927b46f h1:pT+qeeK2nWgSlRaIEKgkY2NoyptIrXc+Rr47ktoB5Fg=
513513
unikraft.com/x/kingkong v0.0.0-20260331102539-2c733927b46f/go.mod h1:x/sY2g/oA3GKDTZyOFC1xArmd6ZySwc4KZlp1MO8a2k=
514-
unikraft.com/x/kraftfile v0.0.0-20260318103446-c2c548a69fc0 h1:uhgXdAhZzAM5AGeymiyeP8zmZGcOj94YYsnc0JmuRTg=
515-
unikraft.com/x/kraftfile v0.0.0-20260318103446-c2c548a69fc0/go.mod h1:OYaIMOzV1IpbZCe2J3SuC5jvT4tAfR0XG9uOPPD+p50=
514+
unikraft.com/x/kraftfile v0.0.0-20260422155551-dcd071f425c2 h1:IUofoVTnhGn1u2Ykz4e2OfUtGZATJVL2AXkrDssms9c=
515+
unikraft.com/x/kraftfile v0.0.0-20260422155551-dcd071f425c2/go.mod h1:OYaIMOzV1IpbZCe2J3SuC5jvT4tAfR0XG9uOPPD+p50=
516516
unikraft.com/x/log v0.0.0-20260126171022-af62c17fcdf7 h1:kFOE7rmK33PiJ2GbWFd3v0WrE8DeAaQsPjrUQ+15CIU=
517517
unikraft.com/x/log v0.0.0-20260126171022-af62c17fcdf7/go.mod h1:f/+5628rnWTnRaRrCDD9mOMf7OV5QmkGIgARlTu4XGE=
518518
unikraft.com/x/ptr v0.0.0-20260126094137-ab6e717e5679 h1:ohptI7loX492JCbbn6yk13hAxysZHyGIZWN8hTw3080=

internal/builder/build.go

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ type BuildOpts struct {
3131

3232
type RootfsOpts struct {
3333
Path string
34-
Type RootfsType
34+
Type kraftfile.SourceType
3535

3636
// Output params
3737
Format kraftfile.FsType
@@ -48,15 +48,6 @@ type RootfsOpts struct {
4848
NoCache bool
4949
}
5050

51-
type RootfsType string
52-
53-
const (
54-
RootfsTypeDockerfile RootfsType = "dockerfile"
55-
RootfsTypeCpio RootfsType = "cpio"
56-
RootfsTypeErofs RootfsType = "erofs"
57-
RootfsTypeDir RootfsType = "dir"
58-
)
59-
6051
// Build a unikraft image based on the provided build options.
6152
func Build(ctx context.Context, opts BuildOpts) ([]*imagespec.Image, error) {
6253
kernels, err := BuildKernel(ctx, opts)

internal/builder/build_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ EOF
4040
Runtime: "unikraft.io/unikraft.org/base",
4141
Rootfs: RootfsOpts{
4242
Format: kraftfile.FsTypeCpio,
43+
Type: kraftfile.SourceTypeDockerfile,
4344
Path: rootfsPath,
4445
},
4546
Platform: []ocispec.Platform{{OS: "fc", Architecture: "x86_64"}},
@@ -64,6 +65,7 @@ EOF
6465
Runtime: "unikraft.io/unikraft.org/base",
6566
Rootfs: RootfsOpts{
6667
Format: kraftfile.FsTypeErofs,
68+
Type: kraftfile.SourceTypeDockerfile,
6769
Path: rootfsPath,
6870
},
6971
Platform: []ocispec.Platform{{OS: "fc", Architecture: "x86_64"}},
@@ -92,6 +94,7 @@ RUN ln -s /etc/passwd /another-test-link
9294
Runtime: "unikraft.io/unikraft.org/base",
9395
Rootfs: RootfsOpts{
9496
Format: kraftfile.FsTypeCpio,
97+
Type: kraftfile.SourceTypeDockerfile,
9598
Path: rootfsPath,
9699
},
97100
Platform: []ocispec.Platform{{OS: "fc", Architecture: "x86_64"}},
@@ -163,6 +166,7 @@ EOF
163166
Runtime: "unikraft.io/unikraft.org/base",
164167
Rootfs: RootfsOpts{
165168
Format: kraftfile.FsTypeCpio,
169+
Type: kraftfile.SourceTypeDockerfile,
166170
Path: rootfsPath,
167171
},
168172
Platform: []ocispec.Platform{
@@ -191,6 +195,7 @@ RUN --mount=type=secret,id=api_key cat /run/secrets/api_key | grep -q s3cr3t
191195
Runtime: "unikraft.io/unikraft.org/base",
192196
Rootfs: RootfsOpts{
193197
Format: kraftfile.FsTypeCpio,
198+
Type: kraftfile.SourceTypeDockerfile,
194199
Path: rootfsPath,
195200
Secrets: secrets,
196201
},
@@ -214,6 +219,7 @@ CMD ["/dockerfile-cmd"]
214219
Runtime: "unikraft.io/unikraft.org/base",
215220
Rootfs: RootfsOpts{
216221
Format: kraftfile.FsTypeCpio,
222+
Type: kraftfile.SourceTypeDockerfile,
217223
Path: rootfsPath,
218224
},
219225
Platform: []ocispec.Platform{{OS: "fc", Architecture: "x86_64"}},

internal/builder/kraftfile.go

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -53,21 +53,17 @@ func KraftfileToBuildOpts(dir string, kf *kraftfile.Kraftfile) (BuildOpts, error
5353
})
5454
}
5555

56-
// FIXME: import detection logic from kraftkit initrd/detect.go
57-
5856
if kf.Rootfs != nil {
57+
opts.Rootfs.Path = kf.Rootfs.Source
5958
opts.Rootfs.Format = kf.Rootfs.Format
60-
sourcePath := filepath.Join(dir, kf.Rootfs.Source)
61-
typ, err := DetectRootfsType(sourcePath)
62-
if err != nil {
63-
return BuildOpts{}, fmt.Errorf("detecting rootfs type for %q: %w", kf.Rootfs.Source, err)
64-
}
65-
opts.Rootfs.Type = typ
66-
switch typ {
67-
case RootfsTypeDockerfile:
68-
opts.Rootfs.Path = filepath.Dir(sourcePath)
69-
default:
70-
opts.Rootfs.Path = sourcePath
59+
opts.Rootfs.Type = kf.Rootfs.Type
60+
if opts.Rootfs.Type == "" {
61+
sourcePath := filepath.Join(dir, kf.Rootfs.Source)
62+
typ, err := DetectSourceType(sourcePath)
63+
if err != nil {
64+
return BuildOpts{}, fmt.Errorf("detecting rootfs type for %q: %w", kf.Rootfs.Source, err)
65+
}
66+
opts.Rootfs.Type = typ
7167
}
7268
}
7369

internal/builder/kraftfile_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ func TestKraftfileToBuildOpts(t *testing.T) {
4646
require.Equal(t, map[string]string{"label": "value"}, opts.Labels)
4747
require.Equal(t, "unikraft.io/unikraft.org/base", opts.Runtime)
4848
require.Equal(t, kraftfile.FsTypeErofs, opts.Rootfs.Format)
49-
require.Equal(t, rootfsDir, opts.Rootfs.Path)
49+
require.Equal(t, "Dockerfile", opts.Rootfs.Path)
50+
require.Equal(t, kraftfile.SourceTypeDockerfile, opts.Rootfs.Type)
5051
require.Len(t, opts.Platform, 1)
5152
require.Equal(t, "x86_64", opts.Platform[0].Architecture)
5253
require.Equal(t, "fc", opts.Platform[0].OS)

internal/builder/rootfs.go

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,15 @@ func buildImageConfig(opts BuildOpts) ocispec.ImageConfig {
5757
return cfg
5858
}
5959

60-
// DetectRootfsType inspects path and returns the detected RootfsType.
61-
func DetectRootfsType(path string) (RootfsType, error) {
60+
// DetectSourceType inspects path and returns the detected RootfsType.
61+
func DetectSourceType(path string) (kraftfile.SourceType, error) {
6262
if path == "" {
6363
return "", fmt.Errorf("empty rootfs path")
6464
}
6565

6666
base := filepath.Base(path)
6767
if base == "Dockerfile" || slices.Contains(strings.Split(base, "."), "Dockerfile") {
68-
return RootfsTypeDockerfile, nil
68+
return kraftfile.SourceTypeDockerfile, nil
6969
}
7070

7171
fi, err := os.Stat(path)
@@ -78,13 +78,13 @@ func DetectRootfsType(path string) (RootfsType, error) {
7878

7979
switch {
8080
case fi.IsDir():
81-
return RootfsTypeDir, nil
81+
return kraftfile.SourceTypeDirectory, nil
8282
case fi.Mode().IsRegular(), fi.Mode()&os.ModeSymlink != 0:
8383
if gocpio.IsValidPath(path) {
84-
return RootfsTypeCpio, nil
84+
return kraftfile.SourceTypeCpio, nil
8585
}
8686
if goerofs.IsValidPath(path) {
87-
return RootfsTypeErofs, nil
87+
return kraftfile.SourceTypeErofs, nil
8888
}
8989
return "", fmt.Errorf("could not detect file rootfs type %q", path)
9090
default:
@@ -93,30 +93,28 @@ func DetectRootfsType(path string) (RootfsType, error) {
9393
}
9494

9595
// BuildRootfs builds a rootfs for each platform in opts.Platform from the
96-
// source at opts.Rootfs.Path. The source is detected in this order:
97-
//
98-
// 1. A pre-packaged rootfs file - returned as-is.
99-
// 2. A directory - walked and archived.
100-
// 3. Anything else - treated as a Dockerfile context and built with BuildKit.
96+
// source at opts.Rootfs.Path.
10197
func BuildRootfs(ctx context.Context, opts BuildOpts) (_ []*imagespec.Image, rerr error) {
10298
if len(opts.Platform) == 0 {
10399
return nil, fmt.Errorf("at least one platform must be specified")
104100
}
105101

106-
if opts.Rootfs.Type == "" {
107-
typ, err := DetectRootfsType(opts.Rootfs.Path)
108-
if err != nil {
109-
return nil, err
110-
}
111-
opts.Rootfs.Type = typ
112-
}
113-
114102
switch opts.Rootfs.Type {
115-
case RootfsTypeCpio, RootfsTypeErofs:
103+
case kraftfile.SourceTypeCpio, kraftfile.SourceTypeErofs:
104+
if opts.Rootfs.Format != "" {
105+
expected := map[kraftfile.SourceType]kraftfile.FsType{
106+
kraftfile.SourceTypeCpio: kraftfile.FsTypeCpio,
107+
kraftfile.SourceTypeErofs: kraftfile.FsTypeErofs,
108+
}
109+
if exp, ok := expected[opts.Rootfs.Type]; ok && opts.Rootfs.Format != exp {
110+
// TODO: maybe we could be smart and convert this
111+
return nil, fmt.Errorf("unsupported rootfs format mismatch: source is %s but requested format is %s", opts.Rootfs.Type, opts.Rootfs.Format)
112+
}
113+
}
116114
return buildRootfsPackaged(ctx, opts)
117-
case RootfsTypeDir:
115+
case kraftfile.SourceTypeDirectory:
118116
return buildRootfsDirectory(ctx, opts)
119-
case RootfsTypeDockerfile:
117+
case kraftfile.SourceTypeDockerfile:
120118
if f, err := os.Stat(opts.Rootfs.Path); err != nil {
121119
if os.IsNotExist(err) {
122120
return nil, fmt.Errorf("dockerfile does not exist")
@@ -127,7 +125,7 @@ func BuildRootfs(ctx context.Context, opts BuildOpts) (_ []*imagespec.Image, rer
127125
}
128126
return buildRootfsDockerfile(ctx, opts)
129127
default:
130-
return nil, fmt.Errorf("unknown rootfs type %q", opts.Rootfs.Type)
128+
return nil, fmt.Errorf("unsupported rootfs type %q", opts.Rootfs.Type)
131129
}
132130
}
133131

0 commit comments

Comments
 (0)