forked from aws/aws-lambda-runtime-interface-emulator
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathmodel.go
More file actions
376 lines (322 loc) · 11.1 KB
/
model.go
File metadata and controls
376 lines (322 loc) · 11.1 KB
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package model
import (
"context"
"encoding/json"
"fmt"
"io"
"os"
"syscall"
"time"
)
// Start, Stop and Configure methods are not used in Core anymore.
// Client interface splitted into Launcher and Executer parts for backward compatibility of dependent packages.
type ContainerSupervisor interface {
Start(context.Context, *StartRequest) error
Configure(context.Context, *ConfigureRequest) error
Stop(context.Context, *StopRequest) (*StopResponse, error)
Freeze(context.Context, *FreezeRequest) (*FreezeResponse, error)
Thaw(context.Context, *ThawRequest) error
Exit(context.Context)
}
type ProcessSupervisor interface {
Exec(context.Context, *ExecRequest) error
Terminate(context.Context, *TerminateRequest) error
Kill(context.Context, *KillRequest) error
Events(context.Context, *EventsRequest) (<-chan Event, error)
}
type SupervisorClient interface {
ContainerSupervisor
ProcessSupervisor
Ping(ctx context.Context) error
}
type StartRequest struct {
Domain string `json:"domain"`
}
type Mount struct {
DriveMount DriveMount
BindMount BindMount
MountType MountType
}
type MountType int
const (
_ MountType = iota
MountTypeDrive
MountTypeBind
)
type CgroupProfileName string
const (
Throttled CgroupProfileName = "throttled"
Unthrottled CgroupProfileName = "unthrottled"
)
func (m *Mount) MarshalJSON() ([]byte, error) {
switch m.MountType {
case MountTypeDrive:
return m.DriveMount.MarshalJSON()
case MountTypeBind:
return m.BindMount.MarshalJSON()
default:
return nil, fmt.Errorf("invalid mount type: %v", m.MountType)
}
}
// Mount in lockhard::mnt is a Rust enum, an algebraic type, where each case has different set of fields.
// This models only the Mount::Drive case, the only one we need for now.
type DriveMount struct {
Source string `json:"source,omitempty"`
Destination string `json:"destination,omitempty"`
FsType string `json:"fs_type,omitempty"`
Options []string `json:"options,omitempty"`
Chowner []uint32 `json:"chowner,omitempty"` // array of two integers representing a tuple
Chmode uint32 `json:"chmode,omitempty"`
// Lockhard also expects a "type" field here, which in our case is constant, so we provide it upon serialization below
}
// Adds the "type": "drive" to json
func (m *DriveMount) MarshalJSON() ([]byte, error) {
type driveMountAlias DriveMount
return json.Marshal(&struct {
Type string `json:"type,omitempty"`
*driveMountAlias
}{
Type: "drive",
driveMountAlias: (*driveMountAlias)(m),
})
}
type BindMount struct {
Source string `json:"source,omitempty"`
Destination string `json:"destination,omitempty"`
Options []string `json:"options,omitempty"`
}
func (m *BindMount) MarshalJSON() ([]byte, error) {
type bindMountAlias BindMount
return json.Marshal(&struct {
Type string `json:"type,omitempty"`
*bindMountAlias
}{
Type: "bind",
bindMountAlias: (*bindMountAlias)(m),
})
}
type Capabilities struct {
Ambient []string `json:"ambient,omitempty"`
Bounding []string `json:"bounding,omitempty"`
Effective []string `json:"effective,omitempty"`
Inheritable []string `json:"inheritable,omitempty"`
Permitted []string `json:"permitted,omitempty"`
}
type CgroupProfiles struct {
Throttled CgroupProfileConfig `json:"throttled"`
Unthrottled CgroupProfileConfig `json:"unthrottled"`
}
type CgroupProfileConfig struct {
CPULimit float64 `json:"cpu_limit"`
MemoryLimitBytes uint64 `json:"memory_limit_bytes"`
}
type ExecUser struct {
UID *uint32 `json:"uid"`
GID *uint32 `json:"gid"`
}
type ConfigureRequest struct {
// domain to configure
Domain string `json:"domain"`
Mounts []Mount `json:"mounts,omitempty"`
Capabilities *Capabilities `json:"capabilities,omitempty"`
SeccompFilters []string `json:"seccomp_filters,omitempty"`
// list of cgroup profiles available for the domain
// cgroup profiles are set on start and thaw request. Start profile
// if configured (as it can vary), thaw profile is always the same (throttled)
CgroupProfiles *CgroupProfiles `json:"cgroup_profiles,omitempty"`
// name of the cgroup profile to enforce at domain start
StartProfile CgroupProfileName `json:"start_profile,omitempty"`
// uid and gid of the user the spawned process runs as (w.r.t. the domain user namespace).
// If nil, Supervisor will use the ExecUser specified in the domain configuration file
ExecUser *ExecUser `json:"exec_user,omitempty"`
// additional hooks to execute on domain start
AdditionalStartHooks []Hook `json:"additional_start_hooks,omitempty"`
}
type EventsRequest struct {
Domain string `json:"domain"`
}
type Event struct {
Time uint64 `json:"timestamp_millis"`
Event EventData `json:"event"`
}
// EventData is a union type tagged by the "EventType"
// and "Cause" strings.
// you can use ProcessTermination() or EventLoss() to access
// the correct type of Event.
type EventData struct {
EvType string `json:"type"`
Domain *string `json:"domain"`
Name *string `json:"name"`
Cause *string `json:"cause"`
Signo *int32 `json:"signo"`
ExitStatus *int32 `json:"exit_status"`
Size *uint64 `json:"size"`
}
// returns nil if the event is not a EventLoss event
// otherwise returns how many events were lost due to
// backpressure (slow reader)
func (d EventData) EventLoss() *uint64 {
return d.Size
}
// Returns a ProcessTermination struct that describe the process
// which terminated. Use Signaled() or Exited() to check whether
// the process terminated because of a signal or exited on its own
func (d EventData) ProcessTerminated() *ProcessTermination {
if d.Signo != nil || d.ExitStatus != nil {
return &ProcessTermination{
Domain: d.Domain,
Name: d.Name,
Signo: d.Signo,
ExitStatus: d.ExitStatus,
}
}
return nil
}
// Event signalling that a process exited
type ProcessTermination struct {
Domain *string
Name *string
Signo *int32
ExitStatus *int32
}
// If not nil, the process was terminated by an unhandled signal.
// The returned value is the number of the signal that terminated the process
func (t ProcessTermination) Signaled() *int32 {
return t.Signo
}
// It not nil, the process exited (as opposed to killed by a signal).
// The returned value is the exit_status returned by the process
func (t ProcessTermination) Exited() *int32 {
return t.ExitStatus
}
func (t ProcessTermination) Success() bool {
return t.ExitStatus != nil && *t.ExitStatus == 0
}
// Transform the process termination status in a string that
// is equal to what would be returned by golang exec.ExitError.Error()
// We used to rely on this format to report errors to customer (sigh)
// so we keep this for backwards compatibility
func (t ProcessTermination) String() string {
if t.ExitStatus != nil {
return fmt.Sprintf("exit status %d", *t.ExitStatus)
}
sig := syscall.Signal(*t.Signo)
return fmt.Sprintf("signal: %s", sig.String())
}
type Hook struct {
// Unique name identifying the hook
Name string `json:"name"`
// Path in the parent domain mount namespace that locates
// the executable to run as the hook
Path string `json:"path"`
// Args for the hook
Args []string `json:"args,omitempty"`
// Map of ENV variables to set when running the hook
Env *map[string]string `json:"envs,omitempty"`
}
type ExecRequest struct {
// Identifier that Supervisor will assign to the spawned process.
// The tuple (Domain,Name) must be unique. It is the caller's responsibility
// to generate the unique name
Name string `json:"name"`
Domain string `json:"domain"`
// Path pointing to the exectuable file within the domain's root filesystem
Path string `json:"path"`
Args []string `json:"args,omitempty"`
// If nil, root of the domain
Cwd *string `json:"cwd,omitempty"`
Env *map[string]string `json:"env,omitempty"`
Logging Logging `json:"log_config"`
StdoutWriter io.Writer `json:"-"`
StderrWriter io.Writer `json:"-"`
ExtraFiles *[]*os.File `json:"-"`
}
// Logging specifies where Supervisor should send Command's logs to
type Logging struct {
Managed ManagedLogging `json:"managed"`
}
type ManagedLogging struct {
Topic ManagedLoggingTopic `json:"topic"`
Formats []ManagedLoggingFormat `json:"formats"`
}
type ManagedLoggingTopic string
const (
RuntimeManagedLoggingTopic ManagedLoggingTopic = "runtime"
RtExtensionManagedLoggingTopic ManagedLoggingTopic = "runtime_extension"
)
type ManagedLoggingFormat string
const (
LineBasedManagedLogging ManagedLoggingFormat = "line"
MessageBasedManagedLogging ManagedLoggingFormat = "message"
)
type ErrorKind string
const (
// operation on an unkown entity (e.g., domain process)
NoSuchEntity ErrorKind = "no_such_entity"
// operation not allowed in the current state (e.g., tried to exec a proces in a domain which is not booted)
InvalidState ErrorKind = "invalid_state"
// Serialization or derserialization issue in the communication
Serde ErrorKind = "serde"
// Unhandled Supervisor server error
Failure ErrorKind = "failure"
)
type SupervisorError struct {
Kind ErrorKind `json:"error_kind"`
Message *string `json:"message"`
}
func (e *SupervisorError) Error() string {
return string(e.Kind)
}
// Send SIGETERM asynchrnously to a process
type TerminateRequest struct {
Name string `json:"name"`
Domain string `json:"domain"`
}
// Force terminate a process (SIGKILL)
// Block until process is exited or timeout
// Deadline needs to be in the future
type KillRequest struct {
Name string `json:"name"`
Domain string `json:"domain"`
Deadline time.Time `json:"deadline"`
}
// Stop the domain.
type StopRequest struct {
Domain string `json:"domain"`
Deadline time.Time `json:"deadline"`
}
type StopResponse struct {
CycleDeltaMetrics CycleDeltaMetrics `json:"cycle_delta_metrics"`
}
type FreezeRequest struct {
Domain string `json:"domain"`
}
type FreezeResponse struct {
CycleDeltaMetrics CycleDeltaMetrics `json:"cycle_delta_metrics"`
}
type MicrovmNetworkInterfaceMetrics struct {
ReceivedBytes uint64 `json:"received_bytes"`
TransmittedBytes uint64 `json:"transmitted_bytes"`
}
type CycleDeltaMetrics struct {
// CPU time (in nanoseconds) obtained by domain cgroup from cpuacct.usage
// https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt
DomainCPURunNs uint64 `json:"domain_cpu_run_ns"`
// time (in nanoseconds) for domain cycle
DomainRunNs uint64 `json:"domain_run_ns"`
// CPU delta time for service cgroup
ServiceCPURunNs uint64 `json:"service_cpu_run_ns"`
// Maximum memory used (in bytes) for domain
DomainMaxMemoryUsageBytes uint64 `json:"domain_max_memory_usage_bytes"`
// CPU delta time (in nanoseconds) obtained from /sys/fs/cgroup/cpu,cpuacct/cpuacct.usage
MicrovmCPURunNs uint64 `json:"microvm_cpu_run_ns"`
// Map with network interface name as key and network metrics as a value
MicrovmNetworksBytes map[string]MicrovmNetworkInterfaceMetrics `json:"microvm_network_interfaces"`
// time ( in nanoseconds ) for idle cpu time
InvokeIdleCPURunNs uint64 `json:"idle_cpu_run_ns"`
}
type ThawRequest struct {
Domain string `json:"domain"`
}