@@ -23,6 +23,7 @@ import (
23
23
"os/exec"
24
24
"path/filepath"
25
25
"strings"
26
+ "sync"
26
27
"syscall"
27
28
28
29
"github.com/firecracker-microvm/firecracker-go-sdk"
@@ -46,10 +47,13 @@ type runcJailer struct {
46
47
runcBinaryPath string
47
48
uid uint32
48
49
gid uint32
50
+ once sync.Once
49
51
}
50
52
51
53
const firecrackerFileName = "firecracker"
52
54
55
+ var configSpec * specs.Spec
56
+
53
57
func newRuncJailer (ctx context.Context , logger * logrus.Entry , ociBundlePath , runcBinPath string , uid , gid uint32 ) (* runcJailer , error ) {
54
58
l := logger .WithField ("ociBundlePath" , ociBundlePath ).
55
59
WithField ("runcBinaryPath" , runcBinPath )
@@ -77,17 +81,17 @@ func newRuncJailer(ctx context.Context, logger *logrus.Entry, ociBundlePath, run
77
81
78
82
// JailPath returns the base directory from where the jail binary will be ran
79
83
// from
80
- func (j runcJailer ) OCIBundlePath () string {
84
+ func (j * runcJailer ) OCIBundlePath () string {
81
85
return j .ociBundlePath
82
86
}
83
87
84
88
// RootPath returns the root fs of the jailed system.
85
- func (j runcJailer ) RootPath () string {
89
+ func (j * runcJailer ) RootPath () string {
86
90
return filepath .Join (j .OCIBundlePath (), rootfsFolder )
87
91
}
88
92
89
93
// JailPath will return the OCI bundle rootfs path
90
- func (j runcJailer ) JailPath () vm.Dir {
94
+ func (j * runcJailer ) JailPath () vm.Dir {
91
95
return vm .Dir (j .RootPath ())
92
96
}
93
97
@@ -100,6 +104,12 @@ func (j *runcJailer) BuildJailedMachine(cfg *Config, machineConfig *firecracker.
100
104
// Build a new client since BuildJailedRootHandler modifies the socket path value.
101
105
client := firecracker .NewClient (machineConfig .SocketPath , j .logger , machineConfig .Debug )
102
106
107
+ if machineConfig .NetNS == "" {
108
+ if netns := getNetNS (configSpec ); netns != "" {
109
+ machineConfig .NetNS = netns
110
+ }
111
+ }
112
+
103
113
opts := []firecracker.Opt {
104
114
firecracker .WithProcessRunner (j .jailerCommand (vmID , cfg .Debug )),
105
115
firecracker .WithClient (client ),
@@ -206,7 +216,7 @@ func (j *runcJailer) BuildJailedRootHandler(cfg *Config, socketPath *string, vmI
206
216
207
217
// BuildLinkFifoHandler will return a new firecracker.Handler with the function
208
218
// that will allow linking of the fifos making them visible to Firecracker.
209
- func (j runcJailer ) BuildLinkFifoHandler () firecracker.Handler {
219
+ func (j * runcJailer ) BuildLinkFifoHandler () firecracker.Handler {
210
220
return firecracker.Handler {
211
221
Name : jailerFifoHandlerName ,
212
222
Fn : func (ctx context.Context , m * firecracker.Machine ) error {
@@ -232,7 +242,7 @@ func (j runcJailer) BuildLinkFifoHandler() firecracker.Handler {
232
242
233
243
// StubDrivesOptions will return a set of options used to create a new stub
234
244
// drive handler.
235
- func (j runcJailer ) StubDrivesOptions () []stubDrivesOpt {
245
+ func (j * runcJailer ) StubDrivesOptions () []stubDrivesOpt {
236
246
return []stubDrivesOpt {
237
247
func (drives []models.Drive ) error {
238
248
for _ , drive := range drives {
@@ -251,7 +261,7 @@ func (j runcJailer) StubDrivesOptions() []stubDrivesOpt {
251
261
// the jail. For block devices we will use mknod to create the device and then
252
262
// set the correct permissions to ensure visibility in the jail. Regular files
253
263
// will be copied into the jail.
254
- func (j runcJailer ) ExposeFileToJail (srcPath string ) error {
264
+ func (j * runcJailer ) ExposeFileToJail (srcPath string ) error {
255
265
uid := j .uid
256
266
gid := j .gid
257
267
@@ -340,7 +350,7 @@ func copyFile(src, dst string, mode os.FileMode) error {
340
350
return nil
341
351
}
342
352
343
- func (j runcJailer ) jailerCommand (containerName string , isDebug bool ) * exec.Cmd {
353
+ func (j * runcJailer ) jailerCommand (containerName string , isDebug bool ) * exec.Cmd {
344
354
cmd := exec .CommandContext (j .ctx , j .runcBinaryPath , "run" , containerName )
345
355
cmd .Dir = j .OCIBundlePath ()
346
356
@@ -353,36 +363,48 @@ func (j runcJailer) jailerCommand(containerName string, isDebug bool) *exec.Cmd
353
363
}
354
364
355
365
// overwriteConfig will set the proper default values if a field had not been set.
356
- //
357
- // TODO: Add netns
358
- func (j runcJailer ) overwriteConfig (cfg * Config , socketPath , configPath string ) error {
359
- spec := specs.Spec {}
360
- configBytes , err := ioutil .ReadFile (configPath )
361
- if err != nil {
362
- return err
363
- }
366
+ func (j * runcJailer ) overwriteConfig (cfg * Config , socketPath , configPath string ) error {
367
+ var err error
368
+ j .once .Do (func () {
369
+ if configSpec == nil {
370
+ spec := specs.Spec {}
371
+ var configBytes []byte
372
+ configBytes , err = ioutil .ReadFile (configPath )
373
+ if err != nil {
374
+ return
375
+ }
364
376
365
- if err : = json .Unmarshal (configBytes , & spec ); err != nil {
366
- return err
367
- }
377
+ if err = json .Unmarshal (configBytes , & spec ); err != nil {
378
+ return
379
+ }
368
380
369
- if spec .Process .User .UID != 0 ||
370
- spec .Process .User .GID != 0 {
371
- return fmt .Errorf (
372
- "using UID %d and GID %d, these values must not be set" ,
373
- spec .Process .User .UID ,
374
- spec .Process .User .GID ,
375
- )
376
- }
381
+ configSpec = & spec
377
382
378
- spec = j .setDefaultConfigValues (cfg , socketPath , spec )
383
+ if spec .Process .User .UID != 0 ||
384
+ spec .Process .User .GID != 0 {
385
+ err = fmt .Errorf (
386
+ "using UID %d and GID %d, these values must not be set" ,
387
+ spec .Process .User .UID ,
388
+ spec .Process .User .GID ,
389
+ )
390
+ return
391
+ }
379
392
380
- spec .Root .Path = rootfsFolder
381
- spec .Root .Readonly = false
393
+ spec = j .setDefaultConfigValues (cfg , socketPath , spec )
394
+ spec .Root .Path = rootfsFolder
395
+ spec .Root .Readonly = false
396
+ }
397
+ })
398
+
399
+ if err != nil {
400
+ return err
401
+ }
402
+
403
+ spec := * configSpec
382
404
spec .Process .User .UID = j .uid
383
405
spec .Process .User .GID = j .gid
384
406
385
- configBytes , err = json .Marshal (& spec )
407
+ configBytes , err : = json .Marshal (& spec )
386
408
if err != nil {
387
409
return err
388
410
}
@@ -396,7 +418,7 @@ func (j runcJailer) overwriteConfig(cfg *Config, socketPath, configPath string)
396
418
397
419
// setDefaultConfigValues will process the spec file provided and allow any
398
420
// empty/zero values to be replaced with default values.
399
- func (j runcJailer ) setDefaultConfigValues (cfg * Config , socketPath string , spec specs.Spec ) specs.Spec {
421
+ func (j * runcJailer ) setDefaultConfigValues (cfg * Config , socketPath string , spec specs.Spec ) specs.Spec {
400
422
if spec .Process == nil {
401
423
spec .Process = & specs.Process {}
402
424
}
@@ -448,3 +470,17 @@ func mkdirAllWithPermissions(path string, mode os.FileMode, uid, gid uint32) err
448
470
449
471
return nil
450
472
}
473
+
474
+ func getNetNS (spec * specs.Spec ) string {
475
+ if spec == nil {
476
+ return ""
477
+ }
478
+
479
+ for _ , ns := range spec .Linux .Namespaces {
480
+ if ns .Type == "network" {
481
+ return ns .Path
482
+ }
483
+ }
484
+
485
+ return ""
486
+ }
0 commit comments