aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver/hub/httphubservice.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/zenserver/hub/httphubservice.cpp')
-rw-r--r--src/zenserver/hub/httphubservice.cpp264
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());
}