in runtime/service.go [313:400]
func (s *service) StartShim(shimCtx context.Context, opts shim.StartOpts) (string, error) {
// In the shim start routine, we can assume that containerd provided a "log" FIFO in the current working dir.
// We have to use that instead of stdout/stderr because containerd reads the stdio pipes of shim start to get
// either the shim address or the error returned here.
logFifo, err := fifo.OpenFifo(shimCtx, "log", unix.O_WRONLY, 0200)
if err != nil {
return "", err
}
logrus.SetOutput(logFifo)
log := log.G(shimCtx).WithField("task_id", opts.ID)
log.Debug("StartShim")
// If we are running a shim start routine, we can safely assume our current working
// directory is the bundle directory
cwd, err := os.Getwd()
if err != nil {
return "", errors.Wrap(err, "failed to get current working directory")
}
bundleDir := bundle.Dir(cwd)
// Since we're running a shim start routine, we need to determine the vmID for the incoming
// container. Start by looking at the container's OCI annotations
s.vmID, err = bundleDir.OCIConfig().VMID()
if err != nil {
return "", err
}
var exitAfterAllTasksDeleted bool
containerCount := 0
if s.vmID == "" {
// If here, no VMID has been provided by the client for this container, so auto-generate a new one.
// This results in a default behavior of running each container in its own VM if not otherwise
// specified by the client.
uuid, err := uuid.NewV4()
if err != nil {
return "", errors.Wrap(err, "failed to generate UUID for VMID")
}
s.vmID = uuid.String()
// This request is handled by a short-lived shim process to find its control socket.
// A long-running shim process won't have the request. So, setting s.logger doesn't affect others.
log = log.WithField("vmID", s.vmID)
// If the client didn't specify a VMID, this is a single-task VM and should thus exit after this
// task is deleted
containerCount = 1
exitAfterAllTasksDeleted = true
}
client, err := ttrpcutil.NewClient(opts.TTRPCAddress)
if err != nil {
return "", err
}
ttrpcClient, err := client.Client()
if err != nil {
return "", err
}
fcControlClient := fccontrolTtrpc.NewFirecrackerClient(ttrpcClient)
_, err = fcControlClient.CreateVM(shimCtx, &proto.CreateVMRequest{
VMID: s.vmID,
ExitAfterAllTasksDeleted: exitAfterAllTasksDeleted,
ContainerCount: int32(containerCount),
})
if err != nil {
errStatus, ok := status.FromError(err)
// ignore AlreadyExists errors, that just means the shim is already up and running
if !ok || errStatus.Code() != codes.AlreadyExists {
return "", errors.Wrap(err, "unexpected error from CreateVM")
}
}
// The shim cannot support traditional -version/-v flag because
// - shim.Run() will call flag.Parse(). So our main cannot call flag.Parse() before that.
// - -address is required and NewService() won't be called if the flag is missing.
// So we log the version informaion here instead
str := ""
if exitAfterAllTasksDeleted {
str = " The VM will be torn down after serving a single task."
}
log.WithField("vmID", s.vmID).Infof("successfully started shim (git commit: %s).%s", revision, str)
return shim.SocketAddress(shimCtx, opts.Address, s.vmID)
}