* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FUNCTION_MASTER_INSTANCE_MANAGER_INSTANCE_MGR_DRIVER_H
#define FUNCTION_MASTER_INSTANCE_MANAGER_INSTANCE_MGR_DRIVER_H
#include <nlohmann/json.hpp>
#include "common/http/http_server.h"
#include "common/status/status.h"
#include "common/utils/module_driver.h"
#include "function_master/instance_manager/quota_manager/quota_manager_actor.h"
#include "group_manager_actor.h"
#include "instance_manager_actor.h"
namespace functionsystem::instance_manager {
const std::string APP_JSON_FORMAT = "application/json";
const std::string JSON_FORMAT = "json";
class InstancesApiRouter : public ApiRouterRegister {
public:
void RegisterHandler(const std::string &url, const HttpHandler &handler) const override
{
ApiRouterRegister::RegisterHandler(url, handler);
};
void InitQueryNamedInsHandler(std::shared_ptr<InstanceManagerActor> imActor)
{
auto namedInsHandler = [imActor](const HttpRequest &request) -> litebus::Future<HttpResponse> {
if (request.method != "GET") {
YRLOG_ERROR("Invalid request method.");
return HttpResponse(litebus::http::ResponseCode::METHOD_NOT_ALLOWED);
}
bool useJsonFormat = request.headers.find("Content-Type") == request.headers.end() ||
request.headers.find("Content-Type")->second == APP_JSON_FORMAT;
auto req = std::make_shared<messages::QueryNamedInsRequest>();
if (request.body.empty() || !req->ParseFromString(request.body)) {
auto requestID = litebus::uuid_generator::UUID::GetRandomUUID().ToString();
req->set_requestid(requestID);
YRLOG_WARN("invalid query namedIns request body. use generated requestID({})", requestID);
}
YRLOG_INFO("{}|query named ins", req->requestid());
return litebus::Async(imActor->GetAID(), &InstanceManagerActor::QueryNamedIns, req)
.Then([useJsonFormat](const messages::QueryNamedInsResponse &rsp)
-> litebus::Future<litebus::http::Response> {
if (!useJsonFormat) {
return litebus::http::Ok(rsp.SerializeAsString());
}
google::protobuf::util::JsonOptions options;
std::string jsonStr;
(void)google::protobuf::util::MessageToJsonString(rsp, &jsonStr, options);
return litebus::http::Ok(jsonStr);
});
};
RegisterHandler("/named-ins", namedInsHandler);
}
void InitQueryInstancesHandler(std::shared_ptr<InstanceManagerActor> imActor)
{
auto handler = [imActor](const HttpRequest &request) -> litebus::Future<HttpResponse> {
if (request.method != "GET") {
YRLOG_ERROR("Invalid request method.");
return HttpResponse(litebus::http::ResponseCode::METHOD_NOT_ALLOWED);
}
bool useJsonFormat = request.headers.find("Type") == request.headers.end() ||
request.headers.find("Type")->second == JSON_FORMAT;
auto req = std::make_shared<messages::QueryInstancesInfoRequest>();
auto requestID = litebus::uuid_generator::UUID::GetRandomUUID().ToString();
req->set_requestid(requestID);
YRLOG_INFO("{}|query instanceinfo", requestID);
return litebus::Async(imActor->GetAID(), &InstanceManagerActor::QueryInstancesInfo, req)
.Then([useJsonFormat](const messages::QueryInstancesInfoResponse &rsp)
-> litebus::Future<litebus::http::Response> {
if (!useJsonFormat) {
return litebus::http::Ok(rsp.SerializeAsString());
}
google::protobuf::util::JsonOptions options;
std::string jsonStr;
(void)google::protobuf::util::MessageToJsonString(rsp, &jsonStr, options);
return litebus::http::Ok(jsonStr);
});
};
RegisterHandler("/queryinstances", handler);
}
void InitQueryDebugInstancesHandler(std::shared_ptr<InstanceManagerActor> imActor)
{
auto handler = [imActor](const HttpRequest &request) -> litebus::Future<HttpResponse> {
if (request.method != "GET") {
YRLOG_ERROR("Invalid request method.");
return HttpResponse(litebus::http::ResponseCode::METHOD_NOT_ALLOWED);
}
bool useJsonFormat = request.headers.find("Type") == request.headers.end() ||
request.headers.find("Type")->second == JSON_FORMAT;
auto req = std::make_shared<messages::QueryDebugInstanceInfosRequest>();
auto requestID = litebus::uuid_generator::UUID::GetRandomUUID().ToString();
req->set_requestid(requestID);
YRLOG_INFO("{}|query debuginstanceinfo", requestID);
return litebus::Async(imActor->GetAID(), &InstanceManagerActor::QueryDebugInstancesInfo, req)
.Then([useJsonFormat](const messages::QueryDebugInstanceInfosResponse &rsp)
-> litebus::Future<litebus::http::Response> {
if (!useJsonFormat) {
return litebus::http::Ok(rsp.SerializeAsString());
}
google::protobuf::util::JsonOptions options;
std::string jsonStr;
(void)google::protobuf::util::MessageToJsonString(rsp, &jsonStr, options);
return litebus::http::Ok(jsonStr);
});
};
RegisterHandler("/query-debug-instances", handler);
}
void InitQueryTenantInstancesHandler(std::shared_ptr<InstanceManagerActor> imActor)
{
auto handler = [imActor](const HttpRequest &request) -> litebus::Future<HttpResponse> {
if (request.method != "GET") {
YRLOG_ERROR("Invalid request method for tenant instances query.");
return HttpResponse(litebus::http::ResponseCode::METHOD_NOT_ALLOWED,
"Only GET method is allowed",
litebus::http::ResponseBodyType::JSON);
}
std::string tenantID;
auto tenantIt = request.url.query.find("tenant_id");
if (tenantIt == request.url.query.end() || tenantIt->second.empty()) {
YRLOG_ERROR("Missing tenant_id parameter in query tenant instances request.");
return HttpResponse(litebus::http::ResponseCode::BAD_REQUEST,
"{\"error\": \"Missing tenant_id parameter\"}",
litebus::http::ResponseBodyType::JSON);
}
tenantID = tenantIt->second;
std::string instanceID;
auto instanceIt = request.url.query.find("instance_id");
if (instanceIt != request.url.query.end() && !instanceIt->second.empty()) {
instanceID = instanceIt->second;
}
bool isSystemTenant = (tenantID == imActor->GetSystemTenantID());
auto req = std::make_shared<messages::QueryInstancesInfoRequest>();
req->set_requestid(litebus::uuid_generator::UUID::GetRandomUUID().ToString());
return litebus::Async(imActor->GetAID(), &InstanceManagerActor::QueryInstancesInfo, req)
.Then([tenantID, instanceID, isSystemTenant](const messages::QueryInstancesInfoResponse &rsp)
-> litebus::Future<litebus::http::Response> {
nlohmann::json instancesArray = nlohmann::json::array();
for (const auto &instance : rsp.instanceinfos()) {
if (isSystemTenant || instance.tenantid() == tenantID) {
if (!instanceID.empty() && instance.instanceid() != instanceID) {
continue;
}
google::protobuf::util::JsonOptions options;
options.add_whitespace = false;
std::string instanceJsonStr;
auto status = google::protobuf::util::MessageToJsonString(
instance, &instanceJsonStr, options);
if (status.ok()) {
nlohmann::json instanceJson = nlohmann::json::parse(instanceJsonStr);
instancesArray.push_back(instanceJson);
} else {
YRLOG_WARN("Failed to convert instance to JSON: {}", status.ToString());
}
}
}
nlohmann::json responseJson;
responseJson["instances"] = instancesArray;
responseJson["count"] = instancesArray.size();
responseJson["tenantID"] = tenantID;
if (isSystemTenant) {
responseJson["isSystemTenant"] = true;
}
if (!instanceID.empty()) {
responseJson["instanceID"] = instanceID;
}
std::string jsonStr = responseJson.dump();
return litebus::http::Ok(jsonStr, litebus::http::ResponseBodyType::JSON);
});
};
RegisterHandler("/query-tenant-instances", handler);
}
};
class InstanceManagerDriver : public ModuleDriver {
public:
explicit InstanceManagerDriver(std::shared_ptr<InstanceManagerActor> instanceManagerActor,
std::shared_ptr<GroupManagerActor> groupManagerActor,
std::shared_ptr<function_master::QuotaManagerActor> quotaManagerActor = nullptr);
~InstanceManagerDriver() override = default;
Status Start() override;
Status Stop() override;
void Await() override;
private:
std::shared_ptr<InstanceManagerActor> instanceManagerActor_{ nullptr };
std::shared_ptr<GroupManagerActor> groupManagerActor_{ nullptr };
std::shared_ptr<function_master::QuotaManagerActor> quotaManagerActor_{ nullptr };
std::shared_ptr<HttpServer> httpServer_{nullptr};
std::shared_ptr<InstancesApiRouter> instanceApiRouteRegister_ = nullptr;
};
}
#endif