Skip to content

Commit 6ba18f8

Browse files
committed
firecracker: Refactoring code
Split image used for network setup with the image used as the source for the rootfs. In the future, some of the qubesome specific logic in the latter should also be transitioned over to the firecracker image, so that the requirements from the workload image are decreased. Signed-off-by: Paulo Gomes <[email protected]>
1 parent aec3e20 commit 6ba18f8

File tree

4 files changed

+90
-96
lines changed

4 files changed

+90
-96
lines changed

internal/runners/firecracker/deps.go

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,53 +11,51 @@ import (
1111
"os"
1212
"os/exec"
1313
"path/filepath"
14+
"strconv"
1415

1516
"github.com/qubesome/cli/internal/files"
17+
"github.com/qubesome/cli/internal/util/dbus"
1618
"golang.org/x/sys/execabs"
19+
20+
_ "embed"
1721
)
1822

19-
const (
20-
command = "/usr/bin/firecracker"
21-
runUserDir = "/run/user/%d"
22-
qubesomeDir = "qubesome"
23-
qubesomeFilemode = 0o700
24-
qubesomeCfgFilemode = 0o600
23+
//go:embed firecracker.config
24+
var configTmpl string
2525

26+
const (
27+
// kernelUrl from https://s3.amazonaws.com/spec.ccfc.min/
2628
kernelURL = "https://s3.amazonaws.com/spec.ccfc.min/firecracker-ci/v1.11/x86_64/vmlinux-6.1.102"
2729
kernelFile = "vmlinux"
2830

31+
// light-weight image that contains the necessary tools for setting up
32+
// firecracker's network taps.
33+
firecrackerImg = "ghcr.io/qubesome/firecracker:latest"
34+
2935
MB = 1024 * 1024
3036
maxDownloadSize = 100 * MB
3137

3238
networkDevName = "tap1"
3339
)
3440

35-
func ensureDependencies(img string) error {
36-
if _, err := exec.LookPath(command); err != nil {
41+
func ensureDependencies() error {
42+
if _, err := exec.LookPath(files.FireCrackerBinary); err != nil {
3743
return err
3844
}
3945

40-
uid := os.Getuid()
41-
baseDir := fmt.Sprintf(runUserDir, uid)
42-
43-
_, err := os.Stat(baseDir)
44-
if err != nil {
45-
return err
46-
}
47-
48-
d := filepath.Join(baseDir, qubesomeDir)
49-
if err = os.MkdirAll(d, qubesomeFilemode); err != nil {
46+
d := files.QubesomeDir()
47+
if err := os.MkdirAll(d, files.DirMode); err != nil {
5048
return err
5149
}
5250

5351
kfile := filepath.Join(d, kernelFile)
54-
_, err = os.Stat(kfile)
52+
_, err := os.Stat(kfile)
5553
if err != nil {
5654
if !errors.Is(err, fs.ErrNotExist) {
5755
return err
5856
}
5957

60-
slog.Info("cached kernel image not found")
58+
dbus.NotifyOrLog("firecracker", "downloading fresh kernel image")
6159
err = download(kernelURL, kfile)
6260
if err != nil {
6361
return fmt.Errorf("failed to download kernel image: %w", err)
@@ -66,19 +64,44 @@ func ensureDependencies(img string) error {
6664

6765
_, err = net.InterfaceByName(networkDevName)
6866
if err != nil {
69-
return setupTaps(img)
67+
return setupTaps()
7068
}
7169

7270
return nil
7371
}
7472

75-
func setupTaps(img string) error {
73+
func createRootFs(dir, img string) (string, error) {
74+
slog.Info("creating root fs")
75+
rootfs := filepath.Join(dir, "roofs.ext4")
76+
bin := files.ContainerRunnerBinary("docker")
77+
cmd := execabs.Command(bin,
78+
"run", "--rm", "--privileged",
79+
"-v", dir+":"+dir,
80+
img,
81+
"create_rootfs", rootfs, strconv.Itoa(os.Getuid()),
82+
)
83+
84+
cmd.Stderr = os.Stderr
85+
cmd.Stdin = os.Stdin
86+
cmd.Stdout = os.Stdout
87+
88+
if err := cmd.Run(); err != nil {
89+
return "", err
90+
}
91+
92+
return rootfs, nil
93+
}
94+
95+
func setupTaps() error {
7696
slog.Info("setting up taps")
7797
bin := files.ContainerRunnerBinary("docker")
98+
99+
slog.Debug("setting up taps", "device name", networkDevName)
78100
cmd := execabs.Command(bin,
79101
"run", "--rm", "--privileged",
80102
"--network", "host",
81-
img,
103+
"-e", fmt.Sprintf("TAP_DEV=%s", networkDevName),
104+
firecrackerImg,
82105
"setup_taps",
83106
)
84107

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"boot-source": {
3+
"kernel_image_path": "{{.KernelImagePath}}",
4+
"boot_args": "keep_bootcon console=ttyS0 reboot=k panic=1 pci=off",
5+
"initrd_path": null
6+
},
7+
"drives": [
8+
{
9+
"drive_id": "rootfs",
10+
"path_on_host": "{{.RootFsPath}}",
11+
"is_root_device": true,
12+
"is_read_only": false,
13+
"partuuid": null,
14+
"cache_type": "Unsafe",
15+
"io_engine": "Sync",
16+
"rate_limiter": null
17+
}
18+
],
19+
"machine-config": {
20+
"vcpu_count": 2,
21+
"mem_size_mib": 256,
22+
"smt": false,
23+
"track_dirty_pages": false
24+
},
25+
"cpu-config": null,
26+
"balloon": null,
27+
"network-interfaces": [
28+
{
29+
"iface_id": "eth0",
30+
"guest_mac": "06:00:AC:10:00:02",
31+
"host_dev_name": "{{.HostDeviceName}}"
32+
}
33+
],
34+
"vsock": null,
35+
"logger": null,
36+
"metrics": null,
37+
"mmds-config": null,
38+
"entropy": null
39+
}

internal/runners/firecracker/run.go

Lines changed: 5 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"log/slog"
77
"os"
88
"path/filepath"
9-
"strconv"
109
"text/template"
1110

1211
"github.com/qubesome/cli/internal/files"
@@ -20,28 +19,6 @@ type configParams struct {
2019
HostDeviceName string
2120
}
2221

23-
func createRootFs(dir, img string) (string, error) {
24-
slog.Info("creating root fs")
25-
rootfs := filepath.Join(dir, "roofs.ext4")
26-
bin := files.ContainerRunnerBinary("docker")
27-
cmd := execabs.Command(bin,
28-
"run", "--rm", "--privileged",
29-
"-v", "/tmp/:/tmp/",
30-
img,
31-
"create_rootfs", rootfs, strconv.Itoa(os.Getuid()),
32-
)
33-
34-
cmd.Stderr = os.Stderr
35-
cmd.Stdin = os.Stdin
36-
cmd.Stdout = os.Stdout
37-
38-
if err := cmd.Run(); err != nil {
39-
return "", err
40-
}
41-
42-
return rootfs, nil
43-
}
44-
4522
func Run(ew types.EffectiveWorkload) error {
4623
slog.Warn("use of firecracker is experimental")
4724

@@ -53,7 +30,7 @@ func Run(ew types.EffectiveWorkload) error {
5330
return fmt.Errorf("firecracker does not support single instance")
5431
}
5532

56-
if err := ensureDependencies(ew.Workload.Image); err != nil {
33+
if err := ensureDependencies(); err != nil {
5734
return err
5835
}
5936

@@ -67,10 +44,7 @@ func Run(ew types.EffectiveWorkload) error {
6744
return err
6845
}
6946

70-
uid := os.Getuid()
71-
baseDir := fmt.Sprintf(runUserDir, uid)
72-
kfile := filepath.Join(baseDir, qubesomeDir, kernelFile)
73-
47+
kfile := filepath.Join(files.QubesomeDir(), kernelFile)
7448
params := configParams{
7549
KernelImagePath: kfile,
7650
RootFsPath: rootfs,
@@ -85,7 +59,7 @@ func Run(ew types.EffectiveWorkload) error {
8559
return err
8660
}
8761

88-
f, err := os.OpenFile(cfgPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, qubesomeCfgFilemode)
62+
f, err := os.OpenFile(cfgPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, files.FileMode)
8963
if err != nil {
9064
return fmt.Errorf("failed to open firecracker config file: %w", err)
9165
}
@@ -105,10 +79,10 @@ func Run(ew types.EffectiveWorkload) error {
10579
}
10680

10781
func run(args []string) error {
108-
slog.Debug(command, "args", args)
82+
slog.Debug(files.FireCrackerBinary, "args", args)
10983

11084
ctx := context.Background()
111-
cmd := execabs.CommandContext(ctx, command, args...)
85+
cmd := execabs.CommandContext(ctx, files.FireCrackerBinary, args...)
11286

11387
cmd.Stdin = os.Stdin
11488
cmd.Stderr = os.Stderr

internal/runners/firecracker/template.go

Lines changed: 0 additions & 42 deletions
This file was deleted.

0 commit comments

Comments
 (0)