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
}