sync code

This commit is contained in:
Ned Wright
2025-08-08 11:10:26 +00:00
parent da20943c09
commit e4747ede14
7 changed files with 684 additions and 0 deletions

View File

@@ -0,0 +1,200 @@
#include "fog_connection.h"
#include <sstream>
#include <fstream>
#include <iostream>
#include <cereal/archives/json.hpp>
#include <cereal/types/vector.hpp>
#include <cereal/types/map.hpp>
#include <cereal/types/string.hpp>
#include "debug.h"
#include "internal/curl_http_client.h"
using namespace std;
USE_DEBUG_FLAG(D_NGINX_MANAGER);
// Helper function to check if HTTPResponse indicates success
bool
isSuccessfulResponse(const HTTPResponse& response)
{
HTTPStatusCode code = response.getHTTPStatusCode();
return (code == HTTPStatusCode::HTTP_OK ||
code == HTTPStatusCode::HTTP_NO_CONTENT ||
code == HTTPStatusCode::HTTP_MULTI_STATUS);
}
FogConnection::FogConnection(const string& token, const string& fog_address)
: var_token(token), var_fog(fog_address), curl_client(std::make_unique<CurlHttpClient>()) {}
void
FogConnection::setProxy(const string& hosts)
{
curl_client->setProxy(hosts);
}
Maybe<void>
FogConnection::getCredentials()
{
AgentRegistrationRequest request;
AgentRegistrationRequest::AuthData auth;
auth.authenticationMethod = "token";
auth.data = var_token;
request.authenticationData.push_back(auth);
request.metaData.agentName = "ConfCollector";
request.metaData.agentType = "Embedded";
request.metaData.platform = "linux";
request.metaData.architecture = "x86";
request.metaData.additionalMetaData["agentVendor"] = "nginx-conf-collector";
stringstream ss_req;
{
cereal::JSONOutputArchive ar(ss_req);
request.serialize(ar);
}
dbgTrace(D_NGINX_MANAGER) << "Registration JSON: " << ss_req.str();
string url = var_fog + "/agents";
map<string, string> headers = {{"Content-Type", "application/json"},
{"User-Agent", "Infinity Next (a7030abf93a4c13)"}};
auto response = curl_client->post(url, ss_req.str(), headers);
dbgTrace(D_NGINX_MANAGER)
<< "Register agent response code: "
<< static_cast<int>(response.getHTTPStatusCode())
<< ", body: "
<< response.getBody();
if (!isSuccessfulResponse(response)) {
return genError("Failed to register agent: HTTP "
+ to_string(static_cast<int>(response.getHTTPStatusCode()))
+ " - "
+ response.getBody());
}
if (response.getBody().find("referenceId") != string::npos) {
return genError("Registration failed: " + response.getBody());
}
try {
AgentRegistrationResponse reg_response;
stringstream ss_res(response.getBody());
cereal::JSONInputArchive ar(ss_res);
reg_response.serialize(ar);
agent_id = reg_response.agentId;
clientId = reg_response.clientId;
clientSecret = reg_response.clientSecret;
tenant_id = reg_response.tenantId;
profile_id = reg_response.profileId;
} catch (const exception& e) {
dbgTrace(D_NGINX_MANAGER) << "Failed to parse registration response: " << response.getBody();
return genError("Failed to parse registration response: " + string(e.what()));
}
return {};
}
Maybe<void>
FogConnection::getJWT()
{
TokenRequest request;
request.login = clientId;
request.password = clientSecret;
stringstream ss_req;
{
cereal::JSONOutputArchive ar(ss_req);
ar(request);
}
string url = var_fog + "/oauth/token?grant_type=client_credentials";
map<string, string> headers = {{"Content-Type", "application/json"},
{"User-Agent", "Infinity Next (a7030abf93a4c13)"}};
dbgTrace(D_NGINX_MANAGER) << "get JWT JSON: " << ss_req.str();
curl_client->setBasicAuth(clientId, clientSecret);
curl_client->authEnabled(true);
auto response = curl_client->post(url, ss_req.str(), headers);
dbgTrace(D_NGINX_MANAGER)
<< "get JWT response code: "
<< static_cast<int>(response.getHTTPStatusCode())
<< ", body: "
<< response.getBody();
if (!isSuccessfulResponse(response)) {
return genError("Failed to get JWT: HTTP "
+ to_string(static_cast<int>(response.getHTTPStatusCode()))
+ " - "
+ response.getBody());
}
if (response.getBody().find("referenceId") != string::npos) {
return genError("JWT request failed: " + response.getBody());
}
try {
TokenResponse token_response;
stringstream ss_res(response.getBody());
cereal::JSONInputArchive ar(ss_res);
token_response.serialize(ar);
ra_token = token_response.access_token;
} catch (const exception& e) {
dbgTrace(D_NGINX_MANAGER) << "Failed to parse JWT response: " << response.getBody();
return genError("Failed to parse JWT response: " + string(e.what()));
}
return {};
}
Maybe<void>
FogConnection::uploadNginxConfig(const string& config_file_path)
{
if (tenant_id.empty() || profile_id.empty() || ra_token.empty()) {
return genError("Missing required data for upload: tenant_id, profile_id, or ra_token");
}
ifstream file(config_file_path, ios::binary);
if (!file.is_open()) {
return genError("Cannot open file: " + config_file_path);
}
string file_content((istreambuf_iterator<char>(file)), istreambuf_iterator<char>());
file.close();
if (file_content.empty()) {
dbgTrace(D_NGINX_MANAGER) << "Warning: Uploading empty file content from " << config_file_path;
}
string upload_url = var_fog + "/agents-core/storage/" + tenant_id + "/nginx/" + profile_id + "/1/nginx.conf";
map<string, string> headers = {
{"Authorization", "Bearer " + ra_token},
{"Content-Type", "text/plain"},
{"User-Agent", "Infinity Next (a7030abf93a4c13)"}
};
auto response = curl_client->put(upload_url, file_content, headers);
dbgTrace(D_NGINX_MANAGER)
<< "Upload status code: "
<< static_cast<int>(response.getHTTPStatusCode())
<< ", body: "
<< response.getBody();
if (!isSuccessfulResponse(response)) {
return genError("Upload failed: HTTP "
+ to_string(static_cast<int>(response.getHTTPStatusCode()))
+ " - "
+ response.getBody());
}
return {};
}

View File

@@ -0,0 +1,33 @@
#ifndef __FOG_CONNECTION_H__
#define __FOG_CONNECTION_H__
#include <string>
#include <vector>
#include <map>
#include "services_sdk/interfaces/i_http_client.h"
#include "req_res_objects.h"
#include "maybe_res.h"
class FogConnection
{
public:
FogConnection(const std::string& token, const std::string& fog_address);
void setProxy(const std::string& hosts);
Maybe<void> getCredentials();
Maybe<void> getJWT();
Maybe<void> uploadNginxConfig(const std::string& config_file_path);
private:
std::string var_token;
std::string var_fog;
std::string agent_id;
std::string tenant_id;
std::string profile_id;
std::string ra_token;
std::string clientId;
std::string clientSecret;
std::unique_ptr<I_HttpClient> curl_client;
};
#endif // __FOG_CONNECTION_H__

View File

@@ -0,0 +1,132 @@
#ifndef __REQ_RES_OBJECTS_H__
#define __REQ_RES_OBJECTS_H__
#include "cereal/archives/json.hpp"
#include "cereal/types/string.hpp"
#include "cereal/types/vector.hpp"
#include "cereal/types/map.hpp"
#include "debug.h"
USE_DEBUG_FLAG(D_NGINX_MANAGER);
struct AgentRegistrationRequest
{
struct AuthData
{
template<class Archive>
void serialize(Archive& ar)
{
try {
ar(cereal::make_nvp("authenticationMethod", authenticationMethod));
ar(cereal::make_nvp("data", data));
} catch (const cereal::Exception &e) {
dbgWarning(D_NGINX_MANAGER) << "Serialization error in AuthData: " << e.what();
ar.setNextName(nullptr);
}
}
std::string authenticationMethod;
std::string data;
};
struct MetaData
{
template<class Archive>
void serialize(Archive& ar)
{
try {
ar(cereal::make_nvp("agentName", agentName));
ar(cereal::make_nvp("agentType", agentType));
ar(cereal::make_nvp("platform", platform));
ar(cereal::make_nvp("architecture", architecture));
for (const auto& pair : additionalMetaData) {
ar(cereal::make_nvp(pair.first.c_str(), pair.second));
}
} catch (const cereal::Exception &e) {
dbgWarning(D_NGINX_MANAGER) << "Serialization error in MetaData: " << e.what();
ar.setNextName(nullptr);
}
}
std::string agentName;
std::string agentType;
std::string platform;
std::string architecture;
std::map<std::string, std::string> additionalMetaData;
};
template<class Archive>
void serialize(Archive& ar)
{
try {
ar(cereal::make_nvp("authenticationData", authenticationData));
ar(cereal::make_nvp("metaData", metaData));
} catch (const cereal::Exception &e) {
dbgWarning(D_NGINX_MANAGER) << "Serialization error in AgentRegistrationRequest: " << e.what();
ar.setNextName(nullptr);
}
}
std::vector<AuthData> authenticationData;
MetaData metaData;
};
struct TokenRequest
{
template<class Archive>
void serialize(Archive& ar)
{
try {
ar(cereal::make_nvp("login", login));
ar(cereal::make_nvp("password", password));
} catch (const cereal::Exception &e) {
dbgWarning(D_NGINX_MANAGER) << "Serialization error in TokenRequest: " << e.what();
ar.setNextName(nullptr);
}
}
std::string login;
std::string password;
};
struct AgentRegistrationResponse
{
template<class Archive>
void serialize(Archive& ar)
{
try {
ar(cereal::make_nvp("agentId", agentId));
ar(cereal::make_nvp("clientId", clientId));
ar(cereal::make_nvp("clientSecret", clientSecret));
ar(cereal::make_nvp("tenantId", tenantId));
ar(cereal::make_nvp("profileId", profileId));
} catch (const cereal::Exception &e) {
dbgWarning(D_NGINX_MANAGER) << "Serialization error in AgentRegistrationResponse: " << e.what();
ar.setNextName(nullptr);
}
}
std::string agentId;
std::string clientId;
std::string clientSecret;
std::string tenantId;
std::string profileId;
};
struct TokenResponse
{
template<class Archive>
void serialize(Archive& ar)
{
try {
ar(cereal::make_nvp("access_token", access_token));
} catch (const cereal::Exception &e) {
dbgWarning(D_NGINX_MANAGER) << "Serialization error in TokenResponse: " << e.what();
ar.setNextName(nullptr);
}
}
std::string access_token;
};
#endif