-
Notifications
You must be signed in to change notification settings - Fork 62
/
runner_kraftfile_unikraft.go
164 lines (133 loc) · 4.47 KB
/
runner_kraftfile_unikraft.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors.
// Licensed under the BSD-3-Clause License (the "License").
// You may not use this file except in compliance with the License.
package run
import (
"context"
"fmt"
"os"
machineapi "kraftkit.sh/api/machine/v1alpha1"
"kraftkit.sh/config"
"kraftkit.sh/unikraft/app"
"kraftkit.sh/unikraft/target"
)
// runnerKraftfileUnikraft is the runner for a path to a project which was built
// from source using the provided unikraft source and any auxiliary microlibrary
// components given a provided target (single) or one specified via the
// -t|--target flag (multiple), e.g.:
//
// $ kraft run // single target in cwd.
// $ kraft run path/to/project // single target at path.
// $ kraft run -t target // multiple targets in cwd.
// $ kraft run -t target path/to/project // multiple targets at path.
type runnerKraftfileUnikraft struct {
workdir string
args []string
project app.Application
}
// String implements Runner.
func (runner *runnerKraftfileUnikraft) String() string {
return "kraftfile-unikraft"
}
// Runnable implements Runner.
func (runner *runnerKraftfileUnikraft) Runnable(ctx context.Context, opts *Run, args ...string) (bool, error) {
var err error
cwd, err := os.Getwd()
if err != nil {
return false, fmt.Errorf("getting current working directory: %w", err)
}
if len(args) == 0 {
runner.workdir = cwd
} else {
runner.workdir = cwd
runner.args = args
if f, err := os.Stat(args[0]); err == nil && f.IsDir() {
runner.workdir = args[0]
runner.args = args[1:]
}
}
if !app.IsWorkdirInitialized(runner.workdir) {
return false, fmt.Errorf("path is not project: %s", runner.workdir)
}
popts := []app.ProjectOption{
app.WithProjectWorkdir(runner.workdir),
}
if len(opts.Kraftfile) > 0 {
popts = append(popts, app.WithProjectKraftfile(opts.Kraftfile))
} else {
popts = append(popts, app.WithProjectDefaultKraftfiles())
}
runner.project, err = app.NewProjectFromOptions(ctx, popts...)
if err != nil {
return false, fmt.Errorf("could not instantiate project directory %s: %v", runner.workdir, err)
}
if runner.project.Unikraft(ctx) == nil {
return false, fmt.Errorf("cannot run project build without unikraft")
}
return true, nil
}
// Prepare implements Runner.
func (runner *runnerKraftfileUnikraft) Prepare(ctx context.Context, opts *Run, machine *machineapi.Machine, args ...string) error {
var err error
// Filter project targets by any provided CLI options
targets := target.Filter(
runner.project.Targets(),
opts.Architecture,
opts.platform.String(),
opts.Target,
)
var t target.Target
switch {
case len(targets) == 0:
return fmt.Errorf("could not detect any project targets based on plat=\"%s\" arch=\"%s\"", opts.platform.String(), opts.Architecture)
case len(targets) == 1:
t = targets[0]
case config.G[config.KraftKit](ctx).NoPrompt && len(targets) > 1:
return fmt.Errorf("could not determine what to run based on provided CLI arguments")
default:
t, err = target.Select(targets)
if err != nil {
return fmt.Errorf("could not select target: %v", err)
}
}
// Provide a meaningful name
targetName := t.Name()
if targetName == runner.project.Name() || targetName == "" {
targetName = t.Platform().Name() + "/" + t.Architecture().Name()
}
machine.Spec.Kernel = "project://" + runner.project.Name() + ":" + targetName
machine.Spec.Architecture = t.Architecture().Name()
machine.Spec.Platform = t.Platform().Name()
if len(runner.args) == 0 {
runner.args = runner.project.Command()
}
if runner.project.Rootfs() != "" && opts.Rootfs == "" {
opts.Rootfs = runner.project.Rootfs()
}
var kernelArgs []string
var appArgs []string
for _, arg := range runner.args {
if arg == "--" {
kernelArgs = appArgs
appArgs = []string{}
continue
}
appArgs = append(appArgs, arg)
}
machine.Spec.KernelArgs = kernelArgs
machine.Spec.ApplicationArgs = appArgs
// Use the symbolic debuggable kernel image?
if opts.WithKernelDbg {
machine.Status.KernelPath = t.KernelDbg()
} else {
machine.Status.KernelPath = t.Kernel()
}
if _, err := os.Stat(machine.Status.KernelPath); err != nil && os.IsNotExist(err) {
return fmt.Errorf("cannot run the selected project target '%s' without building the kernel: try running `kraft build` first: %w", targetName, err)
}
if err := opts.parseKraftfileVolumes(ctx, runner.project, machine); err != nil {
return err
}
return nil
}