func()

in runtime/service.go [940:1063]


func (s *service) buildVMConfiguration(req *proto.CreateVMRequest) (*firecracker.Config, error) {
	for _, driveMount := range req.DriveMounts {
		// Verify the request specified an absolute path for the source/dest of drives.
		// Otherwise, users can implicitly rely on the CWD of this shim or agent.
		if !strings.HasPrefix(driveMount.HostPath, "/") || !strings.HasPrefix(driveMount.VMPath, "/") {
			return nil, errors.Errorf("driveMount %s contains relative path", driveMount.String())
		}
	}

	relSockPath, err := s.shimDir.FirecrackerSockRelPath()
	if err != nil {
		return nil, errors.Wrapf(err, "failed to get relative path to firecracker api socket")
	}

	relVSockPath, err := s.jailer.JailPath().FirecrackerVSockRelPath()
	if err != nil {
		return nil, errors.Wrapf(err, "failed to get relative path to firecracker vsock")
	}

	cfg := firecracker.Config{
		SocketPath: relSockPath,
		VsockDevices: []firecracker.VsockDevice{{
			Path: relVSockPath,
			ID:   "agent_api",
		}},
		MachineCfg: machineConfigurationFromProto(s.config, req.MachineCfg),
		LogLevel:   s.config.DebugHelper.GetFirecrackerLogLevel(),
		VMID:       s.vmID,
	}

	flag, err := internal.SupportCPUTemplate()
	if err != nil {
		return nil, err
	}
	if !flag {
		cfg.MachineCfg.CPUTemplate = ""
	}

	logPath := s.shimDir.FirecrackerLogFifoPath()
	if req.LogFifoPath != "" {
		logPath = req.LogFifoPath
	}
	err = syscall.Mkfifo(logPath, 0700)
	if err != nil {
		return nil, err
	}

	metricsPath := s.shimDir.FirecrackerMetricsFifoPath()
	if req.MetricsFifoPath != "" {
		metricsPath = req.MetricsFifoPath
	}
	err = syscall.Mkfifo(metricsPath, 0700)
	if err != nil {
		return nil, err
	}

	// The Config struct has LogFifo and MetricsFifo, but they will be deprecated since
	// Firecracker doesn't have the corresponding fields anymore.
	cfg.LogPath = logPath
	cfg.MetricsPath = metricsPath

	if req.JailerConfig != nil {
		cfg.NetNS = req.JailerConfig.NetNS
	}

	s.logger.Debugf("using socket path: %s", cfg.SocketPath)

	// Kernel configuration

	if val := req.KernelArgs; val != "" {
		cfg.KernelArgs = val
	} else {
		cfg.KernelArgs = s.config.KernelArgs
	}

	if val := req.KernelImagePath; val != "" {
		cfg.KernelImagePath = val
	} else {
		cfg.KernelImagePath = s.config.KernelImagePath
	}

	cfg.Drives = s.buildRootDrive(req)

	// Drives configuration
	containerCount := int(req.ContainerCount)
	if containerCount < 1 {
		// containerCount should always be positive so that at least one container
		// can run inside the VM. This makes the assumption that a task is going
		// to be run, and to do that at least one container is needed.
		containerCount = 1
	}

	s.containerStubHandler, err = CreateContainerStubs(
		&cfg, s.jailer, containerCount, s.logger)
	if err != nil {
		return nil, errors.Wrapf(err, "failed to create container stub drives")
	}

	s.driveMountStubs, err = CreateDriveMountStubs(
		&cfg, s.jailer, req.DriveMounts, s.logger)
	if err != nil {
		return nil, errors.Wrapf(err, "failed to create drive mount stub drives")
	}

	// If no value for NetworkInterfaces was specified (not even an empty but non-nil list) and
	// the runtime config specifies a default list, use those defaults
	if req.NetworkInterfaces == nil {
		for _, ni := range s.config.DefaultNetworkInterfaces {
			niCopy := ni // we don't want to allow any further calls to modify structs in s.config.DefaultNetworkInterfaces
			req.NetworkInterfaces = append(req.NetworkInterfaces, &niCopy)
		}
	}

	for _, ni := range req.NetworkInterfaces {
		netCfg, err := networkConfigFromProto(ni, s.vmID)
		if err != nil {
			return nil, errors.Wrapf(err, "failed to convert network config %+v", ni)
		}

		cfg.NetworkInterfaces = append(cfg.NetworkInterfaces, *netCfg)
	}

	return &cfg, nil
}