diff options
Diffstat (limited to 'src/zenserver/hub/httphubservice.cpp')
| -rw-r--r-- | src/zenserver/hub/httphubservice.cpp | 264 |
1 files changed, 168 insertions, 96 deletions
diff --git a/src/zenserver/hub/httphubservice.cpp b/src/zenserver/hub/httphubservice.cpp index 34f4294e4..d52da5ae7 100644 --- a/src/zenserver/hub/httphubservice.cpp +++ b/src/zenserver/hub/httphubservice.cpp @@ -8,10 +8,45 @@ #include <zencore/compactbinarybuilder.h> #include <zencore/fmtutils.h> #include <zencore/logging.h> +#include <zenhttp/httpstats.h> namespace zen { -HttpHubService::HttpHubService(Hub& Hub) : m_Hub(Hub) +namespace { + bool HandleFailureResults(HttpServerRequest& Request, const Hub::Response& Resp) + { + if (Resp.ResponseCode == Hub::EResponseCode::Rejected) + { + if (Resp.Message.empty()) + { + Request.WriteResponse(HttpResponseCode::Conflict); + } + else + { + Request.WriteResponse(HttpResponseCode::Conflict, HttpContentType::kText, Resp.Message); + } + return true; + } + if (Resp.ResponseCode == Hub::EResponseCode::NotFound) + { + if (Resp.Message.empty()) + { + Request.WriteResponse(HttpResponseCode::NotFound); + } + else + { + Request.WriteResponse(HttpResponseCode::NotFound, HttpContentType::kText, Resp.Message); + } + return true; + } + return false; + } +} // namespace + +HttpHubService::HttpHubService(Hub& Hub, HttpStatsService& StatsService, HttpStatusService& StatusService) +: m_Hub(Hub) +, m_StatsService(StatsService) +, m_StatusService(StatusService) { using namespace std::literals; @@ -43,6 +78,10 @@ HttpHubService::HttpHubService(Hub& Hub) : m_Hub(Hub) Obj << "moduleId" << ModuleId; Obj << "state" << ToString(Info.State); Obj << "port" << Info.Port; + if (Info.StateChangeTime != std::chrono::system_clock::time_point::min()) + { + Obj << "state_change_time" << ToDateTime(Info.StateChangeTime); + } Obj.BeginObject("process_metrics"); { Obj << "MemoryBytes" << Info.Metrics.MemoryBytes; @@ -83,161 +122,124 @@ HttpHubService::HttpHubService(Hub& Hub) : m_Hub(Hub) [this](HttpRouterRequest& Req) { std::string_view ModuleId = Req.GetCapture(1); - std::string FailureReason = "unknown"; - HttpResponseCode ResponseCode = HttpResponseCode::OK; - try { HubProvisionedInstanceInfo Info; - if (m_Hub.Provision(ModuleId, /* out */ Info, /* out */ FailureReason)) - { - CbObjectWriter Obj; - Obj << "moduleId" << ModuleId; - Obj << "baseUri" << Info.BaseUri; - Obj << "port" << Info.Port; - Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save()); + Hub::Response Resp = m_Hub.Provision(ModuleId, Info); - return; - } - else + if (HandleFailureResults(Req.ServerRequest(), Resp)) { - ResponseCode = HttpResponseCode::BadRequest; + return; } + + const HttpResponseCode HttpCode = + (Resp.ResponseCode == Hub::EResponseCode::Accepted) ? HttpResponseCode::Accepted : HttpResponseCode::OK; + CbObjectWriter Obj; + Obj << "moduleId" << ModuleId; + Obj << "baseUri" << Info.BaseUri; + Obj << "port" << Info.Port; + return Req.ServerRequest().WriteResponse(HttpCode, Obj.Save()); } catch (const std::exception& Ex) { ZEN_ERROR("Exception while provisioning module '{}': {}", ModuleId, Ex.what()); - - FailureReason = Ex.what(); - ResponseCode = HttpResponseCode::InternalServerError; + throw; } - - Req.ServerRequest().WriteResponse(ResponseCode, HttpContentType::kText, FailureReason); }, HttpVerb::kPost); m_Router.RegisterRoute( "modules/{moduleid}/deprovision", [this](HttpRouterRequest& Req) { - std::string_view ModuleId = Req.GetCapture(1); - std::string FailureReason = "unknown"; + std::string_view ModuleId = Req.GetCapture(1); try { - if (!m_Hub.Deprovision(std::string(ModuleId), /* out */ FailureReason)) + Hub::Response Resp = m_Hub.Deprovision(std::string(ModuleId)); + + if (HandleFailureResults(Req.ServerRequest(), Resp)) { - if (FailureReason.empty()) - { - return Req.ServerRequest().WriteResponse(HttpResponseCode::NotFound); - } - else - { - return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, FailureReason); - } + return; } + const HttpResponseCode HttpCode = + (Resp.ResponseCode == Hub::EResponseCode::Accepted) ? HttpResponseCode::Accepted : HttpResponseCode::OK; CbObjectWriter Obj; Obj << "moduleId" << ModuleId; - - return Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save()); + return Req.ServerRequest().WriteResponse(HttpCode, Obj.Save()); } catch (const std::exception& Ex) { ZEN_ERROR("Exception while deprovisioning module '{}': {}", ModuleId, Ex.what()); - - FailureReason = Ex.what(); + throw; } - - Req.ServerRequest().WriteResponse(HttpResponseCode::InternalServerError, HttpContentType::kText, FailureReason); }, HttpVerb::kPost); m_Router.RegisterRoute( "modules/{moduleid}/hibernate", [this](HttpRouterRequest& Req) { - std::string_view ModuleId = Req.GetCapture(1); - std::string FailureReason = "unknown"; + std::string_view ModuleId = Req.GetCapture(1); try { - if (!m_Hub.Hibernate(std::string(ModuleId), /* out */ FailureReason)) + Hub::Response Resp = m_Hub.Hibernate(std::string(ModuleId)); + + if (HandleFailureResults(Req.ServerRequest(), Resp)) { - if (FailureReason.empty()) - { - return Req.ServerRequest().WriteResponse(HttpResponseCode::NotFound); - } - else - { - return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, FailureReason); - } + return; } + const HttpResponseCode HttpCode = + (Resp.ResponseCode == Hub::EResponseCode::Accepted) ? HttpResponseCode::Accepted : HttpResponseCode::OK; CbObjectWriter Obj; Obj << "moduleId" << ModuleId; - - return Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save()); + return Req.ServerRequest().WriteResponse(HttpCode, Obj.Save()); } catch (const std::exception& Ex) { ZEN_ERROR("Exception while hibernating module '{}': {}", ModuleId, Ex.what()); - - FailureReason = Ex.what(); + throw; } - - Req.ServerRequest().WriteResponse(HttpResponseCode::InternalServerError, HttpContentType::kText, FailureReason); }, HttpVerb::kPost); m_Router.RegisterRoute( "modules/{moduleid}/wake", [this](HttpRouterRequest& Req) { - std::string_view ModuleId = Req.GetCapture(1); - std::string FailureReason = "unknown"; + std::string_view ModuleId = Req.GetCapture(1); try { - if (!m_Hub.Wake(std::string(ModuleId), /* out */ FailureReason)) + Hub::Response Resp = m_Hub.Wake(std::string(ModuleId)); + + if (HandleFailureResults(Req.ServerRequest(), Resp)) { - if (FailureReason.empty()) - { - return Req.ServerRequest().WriteResponse(HttpResponseCode::NotFound); - } - else - { - return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, FailureReason); - } + return; } + const HttpResponseCode HttpCode = + (Resp.ResponseCode == Hub::EResponseCode::Accepted) ? HttpResponseCode::Accepted : HttpResponseCode::OK; CbObjectWriter Obj; Obj << "moduleId" << ModuleId; - - return Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save()); + return Req.ServerRequest().WriteResponse(HttpCode, Obj.Save()); } catch (const std::exception& Ex) { ZEN_ERROR("Exception while waking module '{}': {}", ModuleId, Ex.what()); - - FailureReason = Ex.what(); + throw; } - - Req.ServerRequest().WriteResponse(HttpResponseCode::InternalServerError, HttpContentType::kText, FailureReason); }, HttpVerb::kPost); - m_Router.RegisterRoute( - "stats", - [this](HttpRouterRequest& Req) { - CbObjectWriter Obj; - Obj << "currentInstanceCount" << m_Hub.GetInstanceCount(); - Obj << "maxInstanceCount" << m_Hub.GetMaxInstanceCount(); - Obj << "instanceLimit" << m_Hub.GetConfig().InstanceLimit; - Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save()); - }, - HttpVerb::kGet); + m_StatsService.RegisterHandler("hub", *this); + m_StatusService.RegisterHandler("hub", *this); } HttpHubService::~HttpHubService() { + m_StatusService.UnregisterHandler("hub", *this); + m_StatsService.UnregisterHandler("hub", *this); } const char* @@ -254,9 +256,80 @@ HttpHubService::SetNotificationEndpoint(std::string_view UpstreamNotificationEnd } void -HttpHubService::HandleRequest(zen::HttpServerRequest& Request) +HttpHubService::HandleRequest(HttpServerRequest& Request) { - m_Router.HandleRequest(Request); + using namespace std::literals; + + metrics::OperationTiming::Scope $(m_HttpRequests); + if (m_Router.HandleRequest(Request) == false) + { + ZEN_WARN("No route found for {0}", Request.RelativeUri()); + return Request.WriteResponse(HttpResponseCode::NotFound, HttpContentType::kText, "Not found"sv); + } +} + +void +HttpHubService::HandleStatusRequest(HttpServerRequest& Request) +{ + CbObjectWriter Cbo; + Cbo << "ok" << true; + Request.WriteResponse(HttpResponseCode::OK, Cbo.Save()); +} + +void +HttpHubService::HandleStatsRequest(HttpServerRequest& Request) +{ + CbObjectWriter Cbo; + + EmitSnapshot("requests", m_HttpRequests, Cbo); + + Cbo << "currentInstanceCount" << m_Hub.GetInstanceCount(); + Cbo << "maxInstanceCount" << m_Hub.GetMaxInstanceCount(); + Cbo << "instanceLimit" << m_Hub.GetConfig().InstanceLimit; + + SystemMetrics SysMetrics; + DiskSpace Disk; + m_Hub.GetMachineMetrics(SysMetrics, Disk); + Cbo.BeginObject("machine"); + { + Cbo << "disk_free_bytes" << Disk.Free; + Cbo << "disk_total_bytes" << Disk.Total; + Cbo << "memory_avail_mib" << SysMetrics.AvailSystemMemoryMiB; + Cbo << "memory_total_mib" << SysMetrics.SystemMemoryMiB; + Cbo << "virtual_memory_avail_mib" << SysMetrics.AvailVirtualMemoryMiB; + Cbo << "virtual_memory_total_mib" << SysMetrics.VirtualMemoryMiB; + } + Cbo.EndObject(); + + const ResourceMetrics& Limits = m_Hub.GetConfig().ResourceLimits; + Cbo.BeginObject("resource_limits"); + { + Cbo << "disk_bytes" << Limits.DiskUsageBytes; + Cbo << "memory_bytes" << Limits.MemoryUsageBytes; + } + Cbo.EndObject(); + + Request.WriteResponse(HttpResponseCode::OK, Cbo.Save()); +} + +CbObject +HttpHubService::CollectStats() +{ + CbObjectWriter Cbo; + + EmitSnapshot("requests", m_HttpRequests, Cbo); + + Cbo << "currentInstanceCount" << m_Hub.GetInstanceCount(); + Cbo << "maxInstanceCount" << m_Hub.GetMaxInstanceCount(); + Cbo << "instanceLimit" << m_Hub.GetConfig().InstanceLimit; + + return Cbo.Save(); +} + +uint64_t +HttpHubService::GetActivityCounter() +{ + return m_HttpRequests.Count(); } void @@ -288,27 +361,27 @@ HttpHubService::HandleModuleDelete(HttpServerRequest& Request, std::string_view if (InstanceInfo.State == HubInstanceState::Provisioned || InstanceInfo.State == HubInstanceState::Hibernated || InstanceInfo.State == HubInstanceState::Crashed) { - std::string FailureReason; try { - if (!m_Hub.Deprovision(std::string(ModuleId), FailureReason)) + Hub::Response Resp = m_Hub.Deprovision(std::string(ModuleId)); + + if (HandleFailureResults(Request, Resp)) { - if (FailureReason.empty()) - { - Request.WriteResponse(HttpResponseCode::NotFound); - } - else - { - Request.WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, FailureReason); - } return; } + + // TODO: nuke all related storage + + const HttpResponseCode HttpCode = + (Resp.ResponseCode == Hub::EResponseCode::Accepted) ? HttpResponseCode::Accepted : HttpResponseCode::OK; + CbObjectWriter Obj; + Obj << "moduleId" << ModuleId; + return Request.WriteResponse(HttpCode, Obj.Save()); } catch (const std::exception& Ex) { ZEN_ERROR("Exception while deprovisioning module '{}': {}", ModuleId, Ex.what()); - Request.WriteResponse(HttpResponseCode::InternalServerError, HttpContentType::kText, Ex.what()); - return; + throw; } } @@ -316,7 +389,6 @@ HttpHubService::HandleModuleDelete(HttpServerRequest& Request, std::string_view CbObjectWriter Obj; Obj << "moduleId" << ModuleId; - Obj << "state" << ToString(InstanceInfo.State); Request.WriteResponse(HttpResponseCode::OK, Obj.Save()); } |