@@ -23,6 +23,7 @@ import (
2323 "os/exec"
2424 "path/filepath"
2525 "strings"
26+ "sync"
2627 "syscall"
2728
2829 "github.com/firecracker-microvm/firecracker-go-sdk"
@@ -46,8 +47,11 @@ type runcJailer struct {
4647 runcBinaryPath string
4748 uid uint32
4849 gid uint32
50+ once sync.Once
4951}
5052
53+ var configSpec * specs.Spec
54+
5155func newRuncJailer (ctx context.Context , logger * logrus.Entry , ociBundlePath , runcBinPath string , uid , gid uint32 ) (* runcJailer , error ) {
5256 l := logger .WithField ("ociBundlePath" , ociBundlePath ).
5357 WithField ("runcBinaryPath" , runcBinPath )
@@ -75,17 +79,17 @@ func newRuncJailer(ctx context.Context, logger *logrus.Entry, ociBundlePath, run
7579
7680// JailPath returns the base directory from where the jail binary will be ran
7781// from
78- func (j runcJailer ) OCIBundlePath () string {
82+ func (j * runcJailer ) OCIBundlePath () string {
7983 return j .ociBundlePath
8084}
8185
8286// RootPath returns the root fs of the jailed system.
83- func (j runcJailer ) RootPath () string {
87+ func (j * runcJailer ) RootPath () string {
8488 return filepath .Join (j .OCIBundlePath (), rootfsFolder )
8589}
8690
8791// JailPath will return the OCI bundle rootfs path
88- func (j runcJailer ) JailPath () vm.Dir {
92+ func (j * runcJailer ) JailPath () vm.Dir {
8993 return vm .Dir (j .RootPath ())
9094}
9195
@@ -98,6 +102,12 @@ func (j *runcJailer) BuildJailedMachine(cfg *Config, machineConfig *firecracker.
98102 // Build a new client since BuildJailedRootHandler modifies the socket path value.
99103 client := firecracker .NewClient (machineConfig .SocketPath , j .logger , machineConfig .Debug )
100104
105+ if machineConfig .NetNS == "" {
106+ if netns := getNetNS (configSpec ); netns != "" {
107+ machineConfig .NetNS = netns
108+ }
109+ }
110+
101111 opts := []firecracker.Opt {
102112 firecracker .WithProcessRunner (j .jailerCommand (vmID , cfg .Debug )),
103113 firecracker .WithClient (client ),
@@ -213,7 +223,7 @@ func (j *runcJailer) BuildJailedRootHandler(cfg *Config, socketPath *string, vmI
213223
214224// BuildLinkFifoHandler will return a new firecracker.Handler with the function
215225// that will allow linking of the fifos making them visible to Firecracker.
216- func (j runcJailer ) BuildLinkFifoHandler () firecracker.Handler {
226+ func (j * runcJailer ) BuildLinkFifoHandler () firecracker.Handler {
217227 return firecracker.Handler {
218228 Name : jailerFifoHandlerName ,
219229 Fn : func (ctx context.Context , m * firecracker.Machine ) error {
@@ -239,7 +249,7 @@ func (j runcJailer) BuildLinkFifoHandler() firecracker.Handler {
239249
240250// StubDrivesOptions will return a set of options used to create a new stub
241251// drive handler.
242- func (j runcJailer ) StubDrivesOptions () []stubDrivesOpt {
252+ func (j * runcJailer ) StubDrivesOptions () []stubDrivesOpt {
243253 return []stubDrivesOpt {
244254 func (drives []models.Drive ) error {
245255 for _ , drive := range drives {
@@ -258,7 +268,7 @@ func (j runcJailer) StubDrivesOptions() []stubDrivesOpt {
258268// the jail. For block devices we will use mknod to create the device and then
259269// set the correct permissions to ensure visibility in the jail. Regular files
260270// will be copied into the jail.
261- func (j runcJailer ) ExposeFileToJail (srcPath string ) error {
271+ func (j * runcJailer ) ExposeFileToJail (srcPath string ) error {
262272 uid := j .uid
263273 gid := j .gid
264274
@@ -340,7 +350,7 @@ func copyFile(src, dst string, mode os.FileMode) error {
340350 return nil
341351}
342352
343- func (j runcJailer ) jailerCommand (containerName string , isDebug bool ) * exec.Cmd {
353+ func (j * runcJailer ) jailerCommand (containerName string , isDebug bool ) * exec.Cmd {
344354 cmd := exec .CommandContext (j .ctx , j .runcBinaryPath , "run" , containerName )
345355 cmd .Dir = j .OCIBundlePath ()
346356
@@ -353,36 +363,48 @@ func (j runcJailer) jailerCommand(containerName string, isDebug bool) *exec.Cmd
353363}
354364
355365// 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+ }
364376
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+ }
368380
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
377382
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+ }
379392
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
382404 spec .Process .User .UID = j .uid
383405 spec .Process .User .GID = j .gid
384406
385- configBytes , err = json .Marshal (& spec )
407+ configBytes , err : = json .Marshal (& spec )
386408 if err != nil {
387409 return err
388410 }
@@ -396,7 +418,7 @@ func (j runcJailer) overwriteConfig(cfg *Config, socketPath, configPath string)
396418
397419// setDefaultConfigValues will process the spec file provided and allow any
398420// 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 {
400422 if spec .Process == nil {
401423 spec .Process = & specs.Process {}
402424 }
@@ -448,3 +470,17 @@ func mkdirAllWithPermissions(path string, mode os.FileMode, uid, gid uint32) err
448470
449471 return nil
450472}
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