Monorepo for Tangled
tangled.org
1package microvm
2
3import (
4 "context"
5 "fmt"
6 "time"
7
8 "tangled.org/core/spindle/config"
9 "tangled.org/core/spindle/engine"
10 "tangled.org/core/spindle/models"
11)
12
13// memory buffer for qemu process / slirp4netns itself
14const runnerBufferMiB = 96
15
16type Resources struct {
17 MemoryMiB int64
18 VCPUs int64
19 DiskMiB int64
20}
21
22func (r Resources) Fits(limit Resources) bool {
23 if limit.MemoryMiB > 0 && r.MemoryMiB > limit.MemoryMiB {
24 return false
25 }
26 if limit.VCPUs > 0 && r.VCPUs > limit.VCPUs {
27 return false
28 }
29 if limit.DiskMiB > 0 && r.DiskMiB > limit.DiskMiB {
30 return false
31 }
32 return true
33}
34
35func (r Resources) Add(other Resources) Resources {
36 return Resources{
37 MemoryMiB: r.MemoryMiB + other.MemoryMiB,
38 VCPUs: r.VCPUs + other.VCPUs,
39 DiskMiB: r.DiskMiB + other.DiskMiB,
40 }
41}
42
43func (r Resources) Sub(other Resources) Resources {
44 return Resources{
45 MemoryMiB: max(0, r.MemoryMiB-other.MemoryMiB),
46 VCPUs: max(0, r.VCPUs-other.VCPUs),
47 DiskMiB: max(0, r.DiskMiB-other.DiskMiB),
48 }
49}
50
51func (r Resources) String() string {
52 return fmt.Sprintf("memory=%dMiB vcpus=%d disk=%dMiB", r.MemoryMiB, r.VCPUs, r.DiskMiB)
53}
54
55func newVMBudgetConfig(cfg config.MicroVMPipelines) (Resources, Resources, time.Duration) {
56 budget := Resources{
57 MemoryMiB: cfg.MaxTotalMemoryMiB,
58 VCPUs: cfg.MaxTotalVCPUs,
59 DiskMiB: cfg.MaxTotalDiskMiB,
60 }
61 maxReq := Resources{
62 MemoryMiB: cfg.MaxWorkflowMemoryMiB,
63 VCPUs: cfg.MaxWorkflowVCPUs,
64 DiskMiB: cfg.MaxWorkflowDiskMiB,
65 }
66 return budget, maxReq, cfg.AgingThreshold
67}
68
69func (e *Engine) AcquireWorkflowSlot(ctx context.Context, wid models.WorkflowId, wf *models.Workflow) (engine.WorkflowSlot, error) {
70 state, ok := wf.Data.(*workflowState)
71 if !ok || state == nil {
72 return nil, fmt.Errorf("microVM workflow state is not initialized")
73 }
74 if e.scheduler == nil {
75 return engine.NoopSlot{}, nil
76 }
77 req := resourcesForImage(state.ImageSpec)
78 if req.MemoryMiB < 0 || req.VCPUs < 0 || req.DiskMiB < 0 {
79 return nil, fmt.Errorf("microVM resource request must not be negative: %s", req)
80 }
81 return e.scheduler.Acquire(ctx, req)
82}
83
84func resourcesForImage(spec ImageSpec) Resources {
85 var diskMiB int64
86 for _, volume := range spec.Volumes {
87 diskMiB += volume.SizeMiB
88 }
89 return Resources{
90 MemoryMiB: int64(spec.MemoryMiB) + runnerBufferMiB,
91 VCPUs: int64(spec.VCPUs),
92 DiskMiB: diskMiB,
93 }
94}