CreateVM creates new Firecracker VM instance. It creates a runtime shim for the VM and the forwards the CreateVM request to that shim. If there is already a VM created with the provided VMID, then AlreadyExists is returned.
(requestCtx context.Context, req *proto.CreateVMRequest)
| 93 | // the CreateVM request to that shim. If there is already a VM created with the provided VMID, then |
| 94 | // AlreadyExists is returned. |
| 95 | func (s *local) CreateVM(requestCtx context.Context, req *proto.CreateVMRequest) (*proto.CreateVMResponse, error) { |
| 96 | var err error |
| 97 | |
| 98 | id := req.GetVMID() |
| 99 | if err := identifiers.Validate(id); err != nil { |
| 100 | s.logger.WithError(err).Error() |
| 101 | return nil, err |
| 102 | } |
| 103 | |
| 104 | ns, err := namespaces.NamespaceRequired(requestCtx) |
| 105 | if err != nil { |
| 106 | err = fmt.Errorf("error retrieving namespace of request: %w", err) |
| 107 | s.logger.WithError(err).Error() |
| 108 | return nil, err |
| 109 | } |
| 110 | |
| 111 | s.logger.Debugf("using namespace: %s", ns) |
| 112 | |
| 113 | // We determine if there is already a shim managing a VM with the current VMID by attempting |
| 114 | // to listen on the abstract socket address (which is parameterized by VMID). If we get |
| 115 | // EADDRINUSE, then we assume there is already a shim for the VM and return an AlreadyExists error. |
| 116 | shimSocketAddress, err := shim.SocketAddress(requestCtx, s.containerdAddress, id) |
| 117 | if err != nil { |
| 118 | err = fmt.Errorf("failed to obtain shim socket address: %w", err) |
| 119 | s.logger.WithError(err).Error() |
| 120 | return nil, err |
| 121 | } |
| 122 | |
| 123 | shimSocket, err := shim.NewSocket(shimSocketAddress) |
| 124 | if shim.SocketEaddrinuse(err) { |
| 125 | return nil, status.Errorf(codes.AlreadyExists, "VM with ID %q already exists (socket: %q)", id, shimSocketAddress) |
| 126 | } else if err != nil { |
| 127 | err = fmt.Errorf("failed to open shim socket at address %q: %w", shimSocketAddress, err) |
| 128 | s.logger.WithError(err).Error() |
| 129 | return nil, err |
| 130 | } |
| 131 | |
| 132 | // If we're here, there is no pre-existing shim for this VMID, so we spawn a new one |
| 133 | if err := os.Mkdir(s.config.ShimBaseDir, 0700); err != nil && !os.IsExist(err) { |
| 134 | s.logger.WithError(err).Error() |
| 135 | return nil, fmt.Errorf("failed to make shim base directory: %s: %w", s.config.ShimBaseDir, err) |
| 136 | } |
| 137 | |
| 138 | shimDir, err := vm.ShimDir(s.config.ShimBaseDir, ns, id) |
| 139 | if err != nil { |
| 140 | err = fmt.Errorf("failed to build shim path: %w", err) |
| 141 | s.logger.WithError(err).Error() |
| 142 | return nil, err |
| 143 | } |
| 144 | |
| 145 | err = shimDir.Mkdir() |
| 146 | if err != nil { |
| 147 | err = fmt.Errorf("failed to create VM dir %q: %w", shimDir.RootPath(), err) |
| 148 | s.logger.WithError(err).Error() |
| 149 | return nil, err |
| 150 | } |
| 151 | |
| 152 | defer func() { |
nothing calls this directly
no test coverage detected