| 180 | } |
| 181 | |
| 182 | nlohmann::json RpcServer::HandleRequest(const nlohmann::json& request) { |
| 183 | const std::string type = request.value("type", ""); |
| 184 | if (type == "doctor") { |
| 185 | return Ok(ToJson(RunKvmDoctor())); |
| 186 | } |
| 187 | if (type == "system.info") { |
| 188 | return Ok({ |
| 189 | {"data_dir", config_.data_dir}, |
| 190 | {"socket_path", config_.socket_path}, |
| 191 | {"runtime_path", config_.runtime_path}, |
| 192 | {"resources", ToJson(ReadHostResources(config_.data_dir))}, |
| 193 | {"doctor", ToJson(RunKvmDoctor())}, |
| 194 | }); |
| 195 | } |
| 196 | if (type == "vm.list") { |
| 197 | nlohmann::json vms = nlohmann::json::array(); |
| 198 | for (const auto& vm : store_.List()) { |
| 199 | auto item = ToJson(vm); |
| 200 | item["resources"] = VmResources(vm); |
| 201 | vms.push_back(std::move(item)); |
| 202 | } |
| 203 | return Ok({{"vms", std::move(vms)}}); |
| 204 | } |
| 205 | if (type == "vm.create") { |
| 206 | return CreateVm(request); |
| 207 | } |
| 208 | if (type == "vm.edit") { |
| 209 | return EditVm(request); |
| 210 | } |
| 211 | if (type == "vm.delete") { |
| 212 | const std::string vm_id = request.value("vm_id", ""); |
| 213 | // Stop the runtime first so qemu/runtime stops touching the vm_dir |
| 214 | // before we tear it down; otherwise the child process keeps writing |
| 215 | // logs and VmStore::UpdateRuntime keeps emitting runtime_state.json, |
| 216 | // racing the directory removal and resurrecting an orphan dir. |
| 217 | if (auto record = store_.Get(vm_id); record && |
| 218 | (record->runtime.state == VmState::kRunning || |
| 219 | record->runtime.state == VmState::kStarting || |
| 220 | record->runtime.state == VmState::kStopping || |
| 221 | record->runtime.state == VmState::kRebooting)) { |
| 222 | std::string stop_error; |
| 223 | runtime_manager_.StopVm(vm_id, &stop_error); |
| 224 | const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(5); |
| 225 | while (std::chrono::steady_clock::now() < deadline) { |
| 226 | auto current = store_.Get(vm_id); |
| 227 | if (!current || current->runtime.state == VmState::kStopped || |
| 228 | current->runtime.state == VmState::kCrashed) { |
| 229 | break; |
| 230 | } |
| 231 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); |
| 232 | } |
| 233 | } |
| 234 | std::string error; |
| 235 | if (!store_.Remove(vm_id, &error)) return Error("vm_delete_failed", error); |
| 236 | return Ok(); |
| 237 | } |
| 238 | if (type == "vm.start") { |
| 239 | const std::string vm_id = request.value("vm_id", ""); |
nothing calls this directly
no test coverage detected