func()

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
}