Skip to content

Commit 66fe4c2

Browse files
committed
embed init binary in the build for easy self extraction
Signed-off-by: Juan Antonio Osorio <ozz@stacklok.com>
1 parent e6a9962 commit 66fe4c2

5 files changed

Lines changed: 78 additions & 20 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ bin/
44
coverage.out
55
coverage.html
66
.task/
7+
pkg/infra/vm/initbin/waggle-init
78

89
# IDE
910
.idea/

Taskfile.yaml

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ vars:
2222
-X main.buildDate={{.BUILD_DATE}}
2323
2424
# Quick reference:
25-
# task build → Build waggle binary
26-
# task test → Run tests with race detector
27-
# task lint → Run linter
28-
# task verify → fmt + lint + test
25+
# task build → Build waggle binary
26+
# task build-dev → Build waggle + propolis-runner
27+
# task test → Run tests with race detector
28+
# task lint → Run linter
29+
# task verify → fmt + lint + test
2930

3031
tasks:
3132
default:
@@ -35,6 +36,7 @@ tasks:
3536

3637
build:
3738
desc: Build the waggle binary
39+
deps: [build-init]
3840
cmds:
3941
- mkdir -p {{.BUILD_DIR}}
4042
- CGO_ENABLED=0 go build -ldflags "{{.LDFLAGS}}" -o {{.BUILD_DIR}}/{{.BINARY_NAME}} {{.MAIN_PACKAGE}}
@@ -45,24 +47,34 @@ tasks:
4547
generates:
4648
- '{{.BUILD_DIR}}/{{.BINARY_NAME}}'
4749

50+
build-dev:
51+
desc: Build waggle + propolis-runner (requires libkrun-devel)
52+
platforms: [linux]
53+
cmds:
54+
- task: build
55+
- mkdir -p {{.BUILD_DIR}}
56+
- cd ../propolis && CGO_ENABLED=1 go build -o "$OLDPWD/{{.BUILD_DIR}}/propolis-runner" ./runner/cmd/propolis-runner
57+
4858
build-init:
4959
desc: Build the waggle-init binary (guest VM init)
5060
cmds:
51-
- mkdir -p {{.BUILD_DIR}}
52-
- CGO_ENABLED=0 GOOS=linux go build -ldflags "{{.LDFLAGS}}" -o {{.BUILD_DIR}}/waggle-init ./cmd/waggle-init
61+
- mkdir -p pkg/infra/vm/initbin
62+
- CGO_ENABLED=0 GOOS=linux go build -ldflags "{{.LDFLAGS}}" -o pkg/infra/vm/initbin/waggle-init ./cmd/waggle-init
5363
sources:
5464
- cmd/waggle-init/**/*.go
65+
- pkg/infra/vm/initbin/embed.go
5566
- go.mod
5667
- go.sum
5768
generates:
58-
- '{{.BUILD_DIR}}/waggle-init'
69+
- pkg/infra/vm/initbin/waggle-init
5970

6071
build-all:
6172
desc: Build all binaries
6273
deps: [build, build-init]
6374

6475
test:
6576
desc: Run unit tests with race detector
77+
deps: [build-init]
6678
cmds:
6779
- go test -v -race ./...
6880

@@ -75,6 +87,7 @@ tasks:
7587

7688
lint:
7789
desc: Run linter
90+
deps: [build-init]
7891
cmds:
7992
- golangci-lint run ./...
8093

@@ -118,6 +131,7 @@ tasks:
118131
cmds:
119132
- rm -rf {{.BUILD_DIR}}/
120133
- rm -f coverage.out coverage.html
134+
- rm -f pkg/infra/vm/initbin/waggle-init
121135

122136
build-image-python:
123137
desc: Build Python runtime image

pkg/infra/vm/hooks.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package vm
5+
6+
import (
7+
"fmt"
8+
"os"
9+
"path/filepath"
10+
11+
"github.com/stacklok/propolis/image"
12+
13+
"github.com/stacklok/waggle/pkg/infra/vm/initbin"
14+
)
15+
16+
// InjectInitBinary returns a RootFS hook that writes the embedded waggle-init
17+
// binary to /waggle-init in the guest rootfs.
18+
func InjectInitBinary() func(string, *image.OCIConfig) error {
19+
return func(rootfsPath string, _ *image.OCIConfig) error {
20+
initPath := filepath.Join(rootfsPath, "waggle-init")
21+
if err := os.WriteFile(initPath, initbin.Binary, 0o755); err != nil { //nolint:gosec // needs to be executable in the guest
22+
return fmt.Errorf("writing init binary: %w", err)
23+
}
24+
return nil
25+
}
26+
}

pkg/infra/vm/initbin/embed.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
// Package initbin embeds the pre-compiled waggle-init binary.
5+
// The binary is built by `task build-init` and placed at
6+
// pkg/infra/vm/initbin/waggle-init before compiling waggle.
7+
package initbin
8+
9+
import _ "embed"
10+
11+
// Binary contains the embedded waggle-init binary.
12+
//
13+
//go:embed waggle-init
14+
var Binary []byte

pkg/infra/vm/propolis.go

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,19 @@ func (p *PropolisProvider) CreateVM(ctx context.Context, env *environment.Enviro
6666
"ssh_port", env.SSHPort,
6767
)
6868

69+
rootfsHooks := []propolis.RootFSHook{
70+
hooks.InjectAuthorizedKeys(pubKeyContent, hooks.WithKeyUser("/home/sandbox", 1000, 1000)),
71+
}
72+
if opts.InitPath != "" {
73+
hook, err := initInjector(opts.InitPath)
74+
if err != nil {
75+
return nil, err
76+
}
77+
rootfsHooks = append(rootfsHooks, hook)
78+
} else {
79+
rootfsHooks = append(rootfsHooks, InjectInitBinary())
80+
}
81+
6982
// Build propolis options.
7083
propolisOpts := []propolis.Option{
7184
propolis.WithName("waggle-" + env.ID),
@@ -77,24 +90,14 @@ func (p *PropolisProvider) CreateVM(ctx context.Context, env *environment.Enviro
7790
}),
7891
propolis.WithDataDir(envDataDir),
7992

80-
// Inject SSH authorized_keys into the rootfs before boot.
81-
propolis.WithRootFSHook(hooks.InjectAuthorizedKeys(pubKeyContent, hooks.WithKeyUser("/home/sandbox", 1000, 1000))),
93+
// Inject SSH authorized_keys and waggle-init into the rootfs before boot.
94+
propolis.WithRootFSHook(rootfsHooks...),
95+
propolis.WithInitOverride("/waggle-init"),
8296

8397
// Wait for SSH to become ready after boot.
8498
propolis.WithPostBoot(sshReadyWaiter(env.SSHPort, privateKeyPath)),
8599
}
86100

87-
if opts.InitPath != "" {
88-
hook, err := initInjector(opts.InitPath)
89-
if err != nil {
90-
return nil, err
91-
}
92-
propolisOpts = append(propolisOpts,
93-
propolis.WithRootFSHook(hook),
94-
propolis.WithInitOverride("/waggle-init"),
95-
)
96-
}
97-
98101
var backendOpts []libkrun.Option
99102
if opts.RunnerPath != "" {
100103
backendOpts = append(backendOpts, libkrun.WithRunnerPath(opts.RunnerPath))

0 commit comments

Comments
 (0)