in runtime/service.go [520:625]
func (s *service) createVM(requestCtx context.Context, request *proto.CreateVMRequest) (err error) {
var vsockFd *os.File
defer func() {
if vsockFd != nil {
vsockFd.Close()
}
}()
namespace, ok := namespaces.Namespace(s.shimCtx)
if !ok {
namespace = namespaces.Default
}
dir, err := vm.ShimDir(s.config.ShimBaseDir, namespace, s.vmID)
if err != nil {
return err
}
s.logger.Info("creating new VM")
s.jailer, err = newJailer(s.shimCtx, s.logger, dir.RootPath(), s, request)
if err != nil {
return errors.Wrap(err, "failed to create jailer")
}
defer func() {
// in the event of an error, we should stop the VM
if err != nil {
if e := s.jailer.Stop(true); e != nil {
s.logger.WithError(e).Debug("failed to stop firecracker")
}
}
}()
s.machineConfig, err = s.buildVMConfiguration(request)
if err != nil {
return errors.Wrapf(err, "failed to build VM configuration")
}
opts := []firecracker.Opt{}
if v, ok := s.config.DebugHelper.GetFirecrackerSDKLogLevel(); ok {
logger := log.G(s.shimCtx)
logger.Logger.SetLevel(v)
opts = append(opts, firecracker.WithLogger(logger))
}
relVSockPath, err := s.jailer.JailPath().FirecrackerVSockRelPath()
if err != nil {
return errors.Wrapf(err, "failed to get relative path to firecracker vsock")
}
jailedOpts, err := s.jailer.BuildJailedMachine(s.config, s.machineConfig, s.vmID)
if err != nil {
return errors.Wrap(err, "failed to build jailed machine options")
}
if request.BalloonDevice == nil {
s.logger.Debug("No balloon device is setup")
} else {
// Creates a new balloon device if one does not already exist, otherwise updates it, before machine startup.
balloon, err := s.createBalloon(requestCtx, request)
if err != nil {
return errors.Wrap(err, "failed to create balloon device")
}
balloonOpts, err := s.buildBalloonDeviceOpt(balloon)
if err != nil {
return errors.Wrap(err, "failed to create balloon device options")
}
opts = append(opts, balloonOpts...)
}
opts = append(opts, jailedOpts...)
// In the event that a noop jailer is used, we will pass in the shim context
// and have the SDK construct a new machine using that context. Otherwise, a
// custom process runner will be provided via options which will stomp over
// the shim context that was provided here.
s.machine, err = firecracker.NewMachine(s.shimCtx, *s.machineConfig, opts...)
if err != nil {
return errors.Wrapf(err, "failed to create new machine instance")
}
if err = s.machine.Start(s.shimCtx); err != nil {
return errors.Wrapf(err, "failed to start the VM")
}
s.logger.Info("calling agent")
conn, err := vm.VSockDial(requestCtx, s.logger, relVSockPath, defaultVsockPort)
if err != nil {
return errors.Wrapf(err, "failed to dial the VM over vsock")
}
rpcClient := ttrpc.NewClient(conn, ttrpc.WithOnClose(func() { _ = conn.Close() }))
s.agentClient = taskAPI.NewTaskClient(rpcClient)
s.eventBridgeClient = eventbridge.NewGetterClient(rpcClient)
s.driveMountClient = drivemount.NewDriveMounterClient(rpcClient)
s.ioProxyClient = ioproxy.NewIOProxyClient(rpcClient)
s.exitAfterAllTasksDeleted = request.ExitAfterAllTasksDeleted
err = s.mountDrives(requestCtx)
if err != nil {
return err
}
s.logger.Info("successfully started the VM")
return nil
}