Merge pull request #153 from openappsec/Jun_26_2024-Dev

June 27th update
This commit is contained in:
WrightNed 2024-07-01 11:42:11 +03:00 committed by GitHub
commit 01770475ec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
81 changed files with 1783 additions and 702 deletions

View File

@ -4,7 +4,6 @@ add_subdirectory(signal_handler)
add_subdirectory(gradual_deployment)
add_subdirectory(packet)
add_subdirectory(pending_key)
add_subdirectory(health_check_manager)
add_subdirectory(utils)
add_subdirectory(attachment-intakers)

View File

@ -1,8 +0,0 @@
include_directories(${CMAKE_SOURCE_DIR}/components/include)
link_directories(${BOOST_ROOT}/lib)
add_unit_test(
health_check_manager_ut
"health_check_manager_ut.cc"
"singleton;messaging;mainloop;health_check_manager;event_is;metric;-lboost_regex"
)

View File

@ -31,7 +31,7 @@ public:
virtual bool isReverseProxy() = 0;
virtual bool isCloudStorageEnabled() = 0;
virtual Maybe<std::tuple<std::string, std::string, std::string>> parseNginxMetadata() = 0;
virtual Maybe<std::tuple<std::string, std::string, std::string>> readCloudMetadata() = 0;
virtual Maybe<std::tuple<std::string, std::string, std::string, std::string, std::string>> readCloudMetadata() = 0;
virtual std::map<std::string, std::string> getResolvedDetails() = 0;
#if defined(gaia) || defined(smb)
virtual bool compareCheckpointVersion(int cp_version, std::function<bool(int, int)> compare_operator) const = 0;

View File

@ -64,7 +64,7 @@ public:
const std::string &service_id
) = 0;
virtual std::map<std::string, PortNumber> getServiceToPortMap() = 0;
virtual std::map<std::string, std::vector<PortNumber>> getServiceToPortMap() = 0;
protected:
virtual ~I_ServiceController() {}

View File

@ -36,7 +36,6 @@ public:
title,
audience_team,
obj,
false,
MessageCategory::GENERIC,
std::forward<Args>(args)...
)
@ -48,26 +47,6 @@ public:
const std::string &title,
const ReportIS::AudienceTeam &audience_team,
const T &obj,
bool is_async_message,
Args ...args)
:
ReportMessaging(
title,
audience_team,
obj,
is_async_message,
MessageCategory::GENERIC,
std::forward<Args>(args)...
)
{
}
template <typename ...Args, typename T>
ReportMessaging(
const std::string &title,
const ReportIS::AudienceTeam &audience_team,
const T &obj,
bool is_async_message,
const MessageCategory &message_type,
Args ...args)
:
@ -77,7 +56,6 @@ public:
ReportIS::Severity::INFO,
ReportIS::Priority::LOW,
obj,
is_async_message,
message_type,
std::forward<Args>(args)...
)
@ -99,7 +77,6 @@ public:
severity,
priority,
obj,
false,
MessageCategory::GENERIC,
std::forward<Args>(args)...
)
@ -114,7 +91,6 @@ public:
const ReportIS::Severity &severity,
const ReportIS::Priority &priority,
const T &obj,
bool _is_async_message,
const MessageCategory &message_type,
Args ...args)
:
@ -131,7 +107,6 @@ public:
std::chrono::seconds(0),
std::forward<Args>(args)...
),
is_async_message(_is_async_message),
message_type_tag(message_type)
{
report << LogField("eventObject", obj);
@ -141,11 +116,13 @@ public:
ReportMessaging & operator<<(const LogField &field);
Maybe<void, HTTPResponse> sendReportSynchronously();
void setForceBuffering(bool _force_buffering);
private:
Report report;
bool is_async_message;
bool is_async_message = true;
bool force_buffering = false;
MessageCategory message_type_tag;
};

View File

@ -24,6 +24,7 @@ static const string url = "/api/v1/agents/events";
ReportMessaging::~ReportMessaging()
{
if (!Singleton::exists<I_Messaging>()) return;
if (!is_async_message) return;
LogRest log_rest(report);
@ -47,6 +48,25 @@ ReportMessaging::operator<<(const LogField &field)
return *this;
}
class LogRestWithReply : public LogRest
{
public:
LogRestWithReply(const Report &report) : LogRest(report) {}
bool loadJson(const string &) const { return true; }
};
Maybe<void, HTTPResponse>
ReportMessaging::sendReportSynchronously()
{
is_async_message = false;
LogRestWithReply log_rest(report);
auto messaging = Singleton::Consume<I_Messaging>::by<ReportMessaging>();
return messaging->sendSyncMessage(HTTPMethod::POST, url, log_rest, message_type_tag);
}
void
ReportMessaging::setForceBuffering(bool _force_buffering)
{

View File

@ -103,7 +103,48 @@ TEST_F(ReportMessagingTest, title_only)
_
)
).Times(1);
ReportMessaging("test", ReportIS::AudienceTeam::AGENT_CORE, 1, true, ReportIS::Tags::ACCESS_CONTROL);
ReportMessaging("test", ReportIS::AudienceTeam::AGENT_CORE, 1, ReportIS::Tags::ACCESS_CONTROL);
}
TEST_F(ReportMessagingTest, sync_sending)
{
EXPECT_CALL(
mock_messaging,
sendSyncMessage(
_,
_,
"{\n"
" \"log\": {\n"
" \"eventTime\": \"Best Time ever\",\n"
" \"eventName\": \"test\",\n"
" \"eventSeverity\": \"Info\",\n"
" \"eventPriority\": \"Low\",\n"
" \"eventType\": \"Event Driven\",\n"
" \"eventLevel\": \"Log\",\n"
" \"eventLogLevel\": \"info\",\n"
" \"eventAudience\": \"Internal\",\n"
" \"eventAudienceTeam\": \"Agent Core\",\n"
" \"eventFrequency\": 0,\n"
" \"eventTags\": [\n"
" \"Access Control\"\n"
" ],\n"
" \"eventSource\": {\n"
" \"eventTraceId\": \"\",\n"
" \"eventSpanId\": \"\",\n"
" \"issuingEngineVersion\": \"\",\n"
" \"serviceName\": \"Unnamed Nano Service\"\n"
" },\n"
" \"eventData\": {\n"
" \"eventObject\": 1\n"
" }\n"
" }\n"
"}",
_,
_
)
).WillOnce(Return(HTTPResponse(HTTPStatusCode::HTTP_OK, "response!!")));
ReportMessaging report("test", ReportIS::AudienceTeam::AGENT_CORE, 1, ReportIS::Tags::ACCESS_CONTROL);
EXPECT_TRUE(report.sendReportSynchronously().ok());
}
TEST_F(ReportMessagingTest, with_buffering)
@ -144,7 +185,7 @@ TEST_F(ReportMessagingTest, with_buffering)
true
)
).Times(1);
ReportMessaging report("test", ReportIS::AudienceTeam::AGENT_CORE, 1, true, ReportIS::Tags::ACCESS_CONTROL);
ReportMessaging report("test", ReportIS::AudienceTeam::AGENT_CORE, 1, ReportIS::Tags::ACCESS_CONTROL);
report.setForceBuffering(true);
}

View File

@ -361,19 +361,10 @@ private:
<< ", source ip address: "
<< source;
unordered_map<string, set<string>> exception_value_source_ip = {{"sourceIP", {source}}};
auto matched_behavior_maybe = getBehaviorsVerdict(exception_value_source_ip, geo_location_data);
if (matched_behavior_maybe.ok()) {
curr_matched_behavior = matched_behavior_maybe.unpack();
verdict = curr_matched_behavior.first;
dbgDebug(D_GEO_FILTER) << "found sourceIP exception, return verdict";
break;
}
unordered_map<string, set<string>> exception_value_country_code = {
{"countryCode", {country_code}}
};
matched_behavior_maybe = getBehaviorsVerdict(exception_value_country_code, geo_location_data);
auto matched_behavior_maybe = getBehaviorsVerdict(exception_value_country_code, geo_location_data);
if (matched_behavior_maybe.ok()) {
curr_matched_behavior = matched_behavior_maybe.unpack();
verdict = curr_matched_behavior.first;
@ -430,8 +421,11 @@ private:
ReportIS::Tags::HTTP_GEO_FILTER
);
auto env = Singleton::Consume<I_Environment>::by<HttpGeoFilter>();
auto source_ip = env->get<string>(HttpTransactionData::client_ip_ctx);
if (source_ip.ok()) log << LogField("sourceIP", source_ip.unpack());
auto source_ip = env->get<IPAddr>(HttpTransactionData::client_ip_ctx);
if (source_ip.ok()) log << LogField("sourceIP", convertIpAddrToString(source_ip.unpack()));
auto source_identifier = env->get<string>(HttpTransactionData::source_identifier);
if (source_identifier.ok()) log << LogField("httpSourceId", source_identifier.unpack());
auto source_port = env->get<string>(HttpTransactionData::client_port_ctx);
if (source_port.ok()) log << LogField("sourcePort", source_port.unpack());
@ -445,7 +439,7 @@ private:
log << LogField("securityAction", is_prevent ? "Prevent" : "Detect");
if (is_default_action) log << LogField("isDefaultSecurityAction", true);
auto xff = env->get<std::string>(HttpTransactionData::xff_vals_ctx);
auto xff = env->get<string>(HttpTransactionData::xff_vals_ctx);
if (xff.ok()) log << LogField("proxyIP", xff.unpack());
log

View File

@ -12,6 +12,8 @@ add_subdirectory(manifest_controller)
add_subdirectory(update_communication)
add_subdirectory(details_resolver)
add_subdirectory(health_check)
add_subdirectory(health_check_manager)
add_subdirectory(updates_process_reporter)
add_subdirectory(env_details)
#add_subdirectory(orchestration_ut)

View File

@ -45,7 +45,7 @@ public:
bool isVersionAboveR8110() override;
bool isReverseProxy() override;
bool isCloudStorageEnabled() override;
Maybe<tuple<string, string, string>> readCloudMetadata() override;
Maybe<tuple<string, string, string, string, string>> readCloudMetadata() override;
Maybe<tuple<string, string, string>> parseNginxMetadata() override;
#if defined(gaia) || defined(smb)
bool compareCheckpointVersion(int cp_version, std::function<bool(int, int)> compare_operator) const override;
@ -300,19 +300,26 @@ DetailsResolver::Impl::parseNginxMetadata()
return make_tuple(config_opt, cc_opt, nginx_version);
}
Maybe<tuple<string, string, string>>
Maybe<tuple<string, string, string, string, string>>
DetailsResolver::Impl::readCloudMetadata()
{
auto env_read_cloud_metadata = []() -> Maybe<tuple<string, string, string>> {
auto env_read_cloud_metadata = []() -> Maybe<tuple<string, string, string, string, string>> {
string account_id = getenv("CLOUD_ACCOUNT_ID") ? getenv("CLOUD_ACCOUNT_ID") : "";
string vpc_id = getenv("CLOUD_VPC_ID") ? getenv("CLOUD_VPC_ID") : "";
string instance_id = getenv("CLOUD_INSTANCE_ID") ? getenv("CLOUD_INSTANCE_ID") : "";
string instance_local_ip = getenv("CLOUD_INSTANCE_LOCAL_IP") ? getenv("CLOUD_INSTANCE_LOCAL_IP") : "";
string region = getenv("CLOUD_REGION") ? getenv("CLOUD_REGION") : "";
if (account_id.empty() || vpc_id.empty() || instance_id.empty()) {
if (
account_id.empty() ||
vpc_id.empty() ||
instance_id.empty() ||
instance_local_ip.empty() ||
region.empty()) {
return genError("Could not read cloud metadata");
}
return make_tuple(account_id, vpc_id, instance_id);
return make_tuple(account_id, vpc_id, instance_id, instance_local_ip, region);
};
auto cloud_metadata = env_read_cloud_metadata();
@ -347,9 +354,11 @@ DetailsResolver::Impl::readCloudMetadata()
<< "Successfully fetched cloud metadata: "
<< ::get<0>(cloud_metadata.unpack()) << ", "
<< ::get<1>(cloud_metadata.unpack()) << ", "
<< ::get<2>(cloud_metadata.unpack());
<< ::get<2>(cloud_metadata.unpack()) << ", "
<< ::get<3>(cloud_metadata.unpack()) << ", "
<< ::get<4>(cloud_metadata.unpack());
return cloud_metadata.unpack();
return cloud_metadata;
}
DetailsResolver::DetailsResolver() : Component("DetailsResolver"), pimpl(make_unique<Impl>()) {}

View File

@ -58,27 +58,20 @@ checkSAMLPortal(const string &command_output)
Maybe<string>
checkPepIdaIdnStatus(const string &command_output)
{
if (command_output.find("ida_idn_nano_service_enabled=1") != string::npos) {
if (command_output.find("nac_pep_scaled_sharing_enabled = 1") != string::npos) {
return string("true");
}
return genError("Current host does not have PEP control IDA IDN enabled");
}
Maybe<string>
checkAgentIntelligence(const string &command_output)
{
if (command_output.find("is registered") != string::npos) {
return string("true");
}
return genError("Current host does not have agent intelligence installed");
return genError("Current host does not have PEP control scaled_sharing enabled");
}
Maybe<string>
getIDAGaiaPackages(const string &command_output)
{
return string("idaSaml_gaia;idaIdn_gaia;idaIdnBg_gaia;");
string result = "idaSaml_gaia;idaIdn_gaia;idaIdnBg_gaia;";
if (command_output.find("nac_pep_scaled_sharing_enabled = 1") != string::npos) {
result += "agentIntelligenceService_gaia;";
}
return result;
}
Maybe<string>

View File

@ -49,6 +49,9 @@ SHELL_CMD_HANDLER("prerequisitesForHorizonTelemetry",
SHELL_CMD_HANDLER("QUID", "[ -d /opt/CPquid ] "
"&& python3 /opt/CPquid/Quid_Api.py -i /opt/CPotelcol/quid_api/get_global_id.json | jq -r .message || echo ''",
getQUID)
SHELL_CMD_HANDLER("SMO_QUID", "[ -d /opt/CPquid ] "
"&& python3 /opt/CPquid/Quid_Api.py -i /opt/CPotelcol/quid_api/get_smo_quid.json | jq -r .message || echo ''",
getQUID)
SHELL_CMD_HANDLER("hasSDWan", "[ -f $FWDIR/bin/sdwan_steering ] && echo '1' || echo '0'", checkHasSDWan)
SHELL_CMD_HANDLER(
"canUpdateSDWanData",
@ -99,14 +102,8 @@ SHELL_CMD_HANDLER(
SHELL_CMD_HANDLER("hasSAMLSupportedBlade", "enabled_blades", checkSAMLSupportedBlade)
SHELL_CMD_HANDLER("hasIDABlade", "enabled_blades", checkIDABlade)
SHELL_CMD_HANDLER("hasSAMLPortal", "mpclient status nac", checkSAMLPortal)
SHELL_CMD_HANDLER(
"hasAgentIntelligenceInstalled",
"<FILESYSTEM-PREFIX>/watchdog/cp-nano-watchdog "
"--status --service <FILESYSTEM-PREFIX>/agentIntelligence/cp-nano-agent-intelligence-service",
checkAgentIntelligence
)
SHELL_CMD_HANDLER("hasIdaIdnEnabled", "pep control IDN_nano_Srv_support status", checkPepIdaIdnStatus)
SHELL_CMD_HANDLER("requiredNanoServices", "ida_packages", getIDAGaiaPackages)
SHELL_CMD_HANDLER("hasIdaIdnEnabled", "fw ctl get int nac_pep_scaled_sharing_enabled", checkPepIdaIdnStatus)
SHELL_CMD_HANDLER("requiredNanoServices", "fw ctl get int nac_pep_scaled_sharing_enabled", getIDAGaiaPackages)
SHELL_CMD_HANDLER(
"cpProductIntegrationMgmtParentObjectName",
"cat $FWDIR/database/myself_objects.C "

View File

@ -3,5 +3,5 @@ link_directories(${BOOST_ROOT}/lib)
add_unit_test(
health_check_ut
"health_check_ut.cc"
"health_check;messaging;mainloop;singleton;agent_details;config;logging;metric;event_is;health_check_manager;-lboost_regex;-lboost_system"
"health_check;updates_process_reporter;messaging;mainloop;singleton;agent_details;config;logging;metric;event_is;health_check_manager;-lboost_regex;-lboost_system"
)

View File

@ -1,3 +1 @@
add_library(health_check_manager health_check_manager.cc)
add_subdirectory(health_check_manager_ut)

View File

@ -21,6 +21,7 @@
#include "config.h"
#include "cereal/archives/json.hpp"
#include "customized_cereal_map.h"
#include "updates_process_event.h"
using namespace std;
@ -79,19 +80,22 @@ class HealthCheckValue
public:
HealthCheckValue() = default;
HealthCheckValue(HealthCheckStatus raw_status, const map<string, HealthCheckStatusReply> &descriptions)
HealthCheckValue(HealthCheckStatus raw_status, const HealthCheckStatusReply &description)
:
status(raw_status)
{
for (const auto &single_stat : descriptions) {
if (single_stat.second.getStatus() == HealthCheckStatus::HEALTHY) {
dbgTrace(D_HEALTH_CHECK_MANAGER) << "Ignoring healthy status reply. Comp name: " << single_stat.first;
continue;
}
if (description.getStatus() == HealthCheckStatus::HEALTHY) {
dbgTrace(D_HEALTH_CHECK_MANAGER)
<< "Ignoring healthy status reply. Comp name: "
<< description.getCompName();
return;
}
for (const auto &status : single_stat.second.getExtendedStatus()) {
errors.push_back(HealthCheckError(single_stat.first + " " + status.first, status.second));
}
for (const auto &extended_status : description.getExtendedStatus()) {
errors.push_back(
HealthCheckError(description.getCompName() + " " + extended_status.first,
extended_status.second
));
}
}
@ -113,9 +117,9 @@ private:
class HealthCheckPatch : public ClientRest
{
public:
HealthCheckPatch(HealthCheckStatus raw_status, const map<string, HealthCheckStatusReply> &descriptions)
HealthCheckPatch(HealthCheckStatus raw_status, const HealthCheckStatusReply &description)
{
health_check = HealthCheckValue(raw_status, descriptions);
health_check = HealthCheckValue(raw_status, description);
}
C2S_LABEL_PARAM(HealthCheckValue, health_check, "healthCheck");
@ -123,7 +127,8 @@ public:
class HealthCheckManager::Impl
:
Singleton::Provide<I_Health_Check_Manager>::From<HealthCheckManager>
Singleton::Provide<I_Health_Check_Manager>::From<HealthCheckManager>,
public Listener<UpdatesProcessEvent>
{
public:
void
@ -132,6 +137,7 @@ public:
auto rest = Singleton::Consume<I_RestApi>::by<HealthCheckManager>();
rest->addRestCall<HealthCheckOnDemand>(RestAction::SHOW, "health-check-on-demand");
registerListener();
int interval_in_seconds =
getProfileAgentSettingWithDefault<int>(30, "agent.healthCheck.intervalInSeconds");
@ -157,9 +163,62 @@ public:
void
printRepliesHealthStatus(ofstream &oputput_file)
{
getRegisteredComponentsHealthStatus();
cereal::JSONOutputArchive ar(oputput_file);
ar(cereal::make_nvp("allComponentsHealthCheckReplies", all_comps_health_status));
ar(cereal::make_nvp(health_check_reply.getCompName(), health_check_reply));
}
void
upon(const UpdatesProcessEvent &event)
{
OrchestrationStatusFieldType status_field_type = event.getStatusFieldType();
HealthCheckStatus _status = convertResultToHealthCheckStatus(event.getResult());
string status_field_type_str = convertOrchestrationStatusFieldTypeToStr(status_field_type);
extended_status[status_field_type_str] =
_status == HealthCheckStatus::HEALTHY ?
"Success" :
event.parseDescription();
field_types_status[status_field_type_str] = _status;
switch(_status) {
case HealthCheckStatus::UNHEALTHY: {
general_health_aggregated_status = HealthCheckStatus::UNHEALTHY;
break;
}
case HealthCheckStatus::DEGRADED: {
for (const auto &type_status : field_types_status) {
if ((type_status.first != status_field_type_str)
&& (type_status.second == HealthCheckStatus::UNHEALTHY))
{
break;
}
}
general_health_aggregated_status = HealthCheckStatus::DEGRADED;
break;
}
case HealthCheckStatus::HEALTHY: {
for (const auto &type_status : field_types_status) {
if ((type_status.first != status_field_type_str)
&& (type_status.second == HealthCheckStatus::UNHEALTHY
|| type_status.second == HealthCheckStatus::DEGRADED)
)
{
break;
}
general_health_aggregated_status = HealthCheckStatus::HEALTHY;
}
break;
}
case HealthCheckStatus::IGNORED: {
break;
}
}
health_check_reply = HealthCheckStatusReply(
"Orchestration",
general_health_aggregated_status,
extended_status
);
}
private:
@ -168,9 +227,10 @@ private:
{
dbgFlow(D_HEALTH_CHECK_MANAGER) << "Sending a health check patch";
HealthCheckPatch patch_to_send(general_health_aggregated_status, all_comps_health_status);
auto messaging = Singleton::Consume<I_Messaging>::by<HealthCheckManager>();
return messaging->sendSyncMessageWithoutResponse(
HealthCheckPatch patch_to_send(general_health_aggregated_status, health_check_reply);
extended_status.clear();
field_types_status.clear();
return Singleton::Consume<I_Messaging>::by<HealthCheckManager>()->sendSyncMessageWithoutResponse(
HTTPMethod::PATCH,
"/agents",
patch_to_send,
@ -178,59 +238,11 @@ private:
);
}
void
getRegisteredComponentsHealthStatus()
{
vector<HealthCheckStatusReply> health_check_event_reply = HealthCheckStatusEvent().query();
all_comps_health_status.clear();
for (const auto &reply : health_check_event_reply) {
if (reply.getStatus() != HealthCheckStatus::IGNORED) {
all_comps_health_status.emplace(reply.getCompName(), reply);
}
}
}
void
calcGeneralHealthAggregatedStatus()
{
general_health_aggregated_status = HealthCheckStatus::HEALTHY;
for (const auto &reply : all_comps_health_status) {
HealthCheckStatus status = reply.second.getStatus();
dbgTrace(D_HEALTH_CHECK_MANAGER)
<< "Current aggregated status is: "
<< HealthCheckStatusReply::convertHealthCheckStatusToStr(
general_health_aggregated_status
)
<< ". Got health status: "
<< HealthCheckStatusReply::convertHealthCheckStatusToStr(status)
<< "for component: "
<< reply.first;
switch (status) {
case HealthCheckStatus::UNHEALTHY : {
general_health_aggregated_status = HealthCheckStatus::UNHEALTHY;
return;
}
case HealthCheckStatus::DEGRADED : {
general_health_aggregated_status = HealthCheckStatus::DEGRADED;
break;
}
case HealthCheckStatus::IGNORED : break;
case HealthCheckStatus::HEALTHY : break;
}
}
}
void
executeHealthCheck()
{
dbgFlow(D_HEALTH_CHECK_MANAGER) << "Collecting health status from all registered components.";
getRegisteredComponentsHealthStatus();
calcGeneralHealthAggregatedStatus();
dbgTrace(D_HEALTH_CHECK_MANAGER)
<< "Aggregated status: "
<< HealthCheckStatusReply::convertHealthCheckStatusToStr(general_health_aggregated_status);
@ -244,9 +256,43 @@ private:
};
}
HealthCheckStatus general_health_aggregated_status;
map<string, HealthCheckStatusReply> all_comps_health_status;
string
convertOrchestrationStatusFieldTypeToStr(OrchestrationStatusFieldType type)
{
switch (type) {
case OrchestrationStatusFieldType::REGISTRATION : return "Registration";
case OrchestrationStatusFieldType::MANIFEST : return "Manifest";
case OrchestrationStatusFieldType::LAST_UPDATE : return "Last Update";
case OrchestrationStatusFieldType::COUNT : return "Count";
}
dbgAssert(false) << "Trying to convert unknown orchestration status field to string.";
return "";
}
HealthCheckStatus
convertResultToHealthCheckStatus(UpdatesProcessResult result)
{
switch (result) {
case UpdatesProcessResult::SUCCESS : return HealthCheckStatus::HEALTHY;
case UpdatesProcessResult::UNSET : return HealthCheckStatus::IGNORED;
case UpdatesProcessResult::FAILED : return HealthCheckStatus::UNHEALTHY;
case UpdatesProcessResult::DEGRADED : return HealthCheckStatus::DEGRADED;
}
dbgAssert(false) << "Trying to convert unknown update process result field to health check status.";
return HealthCheckStatus::IGNORED;
}
HealthCheckStatus general_health_aggregated_status = HealthCheckStatus::HEALTHY;
HealthCheckStatusReply health_check_reply = HealthCheckStatusReply(
"Orchestration",
HealthCheckStatus::HEALTHY,
{}
);
bool should_patch_report;
map<string, string> extended_status;
map<string, HealthCheckStatus> field_types_status;
};
HealthCheckManager::HealthCheckManager() : Component("HealthCheckManager"), pimpl(make_unique<Impl>()) {}

View File

@ -13,42 +13,13 @@
#include "mock/mock_mainloop.h"
#include "mock/mock_messaging.h"
#include "mock/mock_rest_api.h"
#include "updates_process_event.h"
using namespace std;
using namespace testing;
USE_DEBUG_FLAG(D_HEALTH_CHECK);
class TestHealthCheckStatusListener : public Listener<HealthCheckStatusEvent>
{
public:
void upon(const HealthCheckStatusEvent &) override {}
HealthCheckStatusReply
respond(const HealthCheckStatusEvent &) override
{
map<string, string> extended_status;
extended_status["team"] = team;
extended_status["city"] = city;
HealthCheckStatusReply reply(comp_name, status, extended_status);
return reply;
}
void setStatus(HealthCheckStatus new_status) { status = new_status; }
string getListenerName() const { return "TestHealthCheckStatusListener"; }
private:
static const string comp_name;
HealthCheckStatus status = HealthCheckStatus::HEALTHY;
static const string team;
static const string city;
};
const string TestHealthCheckStatusListener::comp_name = "Test";
const string TestHealthCheckStatusListener::team = "Hapoel";
const string TestHealthCheckStatusListener::city = "Tel-Aviv";
class TestEnd {};
class HealthCheckManagerTest : public Test
@ -56,8 +27,7 @@ class HealthCheckManagerTest : public Test
public:
HealthCheckManagerTest()
{
Debug::setNewDefaultStdout(&debug_output);
Debug::setUnitTestFlag(D_HEALTH_CHECK, Debug::DebugLevel::INFO);
Debug::setUnitTestFlag(D_HEALTH_CHECK, Debug::DebugLevel::NOISE);
EXPECT_CALL(mock_ml, addRecurringRoutine(_, _, _, _, _)).WillRepeatedly(
DoAll(SaveArg<2>(&health_check_periodic_routine), Return(1))
@ -70,7 +40,6 @@ public:
);
env.preload();
event_listener.registerListener();
env.init();
@ -98,14 +67,12 @@ public:
StrictMock<MockMainLoop> mock_ml;
StrictMock<MockRestApi> mock_rest;
StrictMock<MockMessaging> mock_message;
stringstream debug_output;
ConfigComponent config;
Config::I_Config *i_config = nullptr;
::Environment env;
HealthCheckManager health_check_manager;
I_Health_Check_Manager *i_health_check_manager;
unique_ptr<ServerRest> health_check_server;
TestHealthCheckStatusListener event_listener;
};
TEST_F(HealthCheckManagerTest, runPeriodicHealthCheckTest)
@ -142,7 +109,20 @@ TEST_F(HealthCheckManagerTest, runPeriodicHealthCheckTest)
EXPECT_EQ(actual_body, expected_healthy_body);
EXPECT_EQ("Healthy", aggregated_status_str);
event_listener.setStatus(HealthCheckStatus::DEGRADED);
UpdatesProcessEvent(
UpdatesProcessResult::DEGRADED,
UpdatesConfigType::SETTINGS,
UpdatesFailureReason::DOWNLOAD_FILE,
"setting.json",
"File not found"
).notify();
UpdatesProcessEvent(
UpdatesProcessResult::DEGRADED,
UpdatesConfigType::MANIFEST,
UpdatesFailureReason::DOWNLOAD_FILE,
"manifest.json",
"File not found"
).notify();
try {
health_check_periodic_routine();
} catch (const TestEnd &t) {}
@ -156,16 +136,16 @@ TEST_F(HealthCheckManagerTest, runPeriodicHealthCheckTest)
" \"status\": \"Degraded\",\n"
" \"errors\": [\n"
" {\n"
" \"code\": \"Test city\",\n"
" \"code\": \"Orchestration Last Update\",\n"
" \"message\": [\n"
" \"Tel-Aviv\"\n"
" \"Failed to download the file setting.json. Error: File not found\"\n"
" ],\n"
" \"internal\": true\n"
" },\n"
" {\n"
" \"code\": \"Test team\",\n"
" \"code\": \"Orchestration Manifest\",\n"
" \"message\": [\n"
" \"Hapoel\"\n"
" \"Failed to download the file manifest.json. Error: File not found\"\n"
" ],\n"
" \"internal\": true\n"
" }\n"
@ -196,19 +176,24 @@ TEST_F(HealthCheckManagerTest, runOnDemandHealthCheckTest)
config.preload();
Singleton::Consume<Config::I_Config>::from(config)->loadConfiguration(ss);
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::MANIFEST,
UpdatesFailureReason::DOWNLOAD_FILE,
"manifest.json",
"File not found"
).notify();
stringstream is;
is << "{}";
health_check_server->performRestCall(is);
string expected_status =
"{\n"
" \"allComponentsHealthCheckReplies\": {\n"
" \"Test\": {\n"
" \"status\": \"Healthy\",\n"
" \"extendedStatus\": {\n"
" \"city\": \"Tel-Aviv\",\n"
" \"team\": \"Hapoel\"\n"
" }\n"
" \"Orchestration\": {\n"
" \"status\": \"Unhealthy\",\n"
" \"extendedStatus\": {\n"
" \"Manifest\": \"Failed to download the file manifest.json. Error: File not found\"\n"
" }\n"
" }\n"
"}";

View File

@ -26,6 +26,13 @@ operator<<(std::ostream &os, const Maybe<std::tuple<std::string, std::string, st
return os;
}
std::ostream &
operator<<(
std::ostream &os, const Maybe<std::tuple<std::string, std::string, std::string, std::string, std::string>> &)
{
return os;
}
class MockDetailsResolver
:
public Singleton::Provide<I_DetailsResolver>::From<MockProvider<I_DetailsResolver>>
@ -42,7 +49,8 @@ public:
MOCK_METHOD0(getResolvedDetails, std::map<std::string, std::string>());
MOCK_METHOD0(isVersionAboveR8110, bool());
MOCK_METHOD0(parseNginxMetadata, Maybe<std::tuple<std::string, std::string, std::string>>());
MOCK_METHOD0(readCloudMetadata, Maybe<std::tuple<std::string, std::string, std::string>>());
MOCK_METHOD0(
readCloudMetadata, Maybe<std::tuple<std::string, std::string, std::string, std::string, std::string>>());
};
#endif // __MOCK_DETAILS_RESOLVER_H__

View File

@ -64,7 +64,7 @@ public:
)
);
typedef std::map<std::string, PortNumber> ServicePortMap;
typedef std::map<std::string, std::vector<PortNumber>> ServicePortMap;
MOCK_METHOD0(getServiceToPortMap, ServicePortMap());
MOCK_METHOD3(updateReconfStatus, void(int id, const std::string &service_name, ReconfStatus status));
MOCK_METHOD4(

View File

@ -0,0 +1,130 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (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 __UPDATES_PROCESS_EVENT_H__
#define __UPDATES_PROCESS_EVENT_H__
#include "event.h"
#include "singleton.h"
#include "config.h"
#include "debug.h"
#include "i_orchestration_status.h"
#include "health_check_status/health_check_status.h"
#include "customized_cereal_map.h"
USE_DEBUG_FLAG(D_UPDATES_PROCESS_REPORTER);
enum class UpdatesFailureReason {
CHECK_UPDATE,
REGISTRATION,
ORCHESTRATION_SELF_UPDATE,
GET_UPDATE_REQUEST,
DOWNLOAD_FILE,
HANDLE_FILE,
INSTALLATION_QUEUE,
INSTALL_PACKAGE,
CHECKSUM_UNMATCHED,
POLICY_CONFIGURATION,
POLICY_FOG_CONFIGURATION,
NONE
};
enum class UpdatesConfigType { MANIFEST, POLICY, SETTINGS, DATA, GENERAL };
enum class UpdatesProcessResult { UNSET, SUCCESS, FAILED, DEGRADED };
static inline std::string
convertUpdatesFailureReasonToStr(UpdatesFailureReason reason)
{
switch (reason) {
case UpdatesFailureReason::CHECK_UPDATE : return "CHECK_UPDATE";
case UpdatesFailureReason::REGISTRATION : return "REGISTRATION";
case UpdatesFailureReason::ORCHESTRATION_SELF_UPDATE : return "ORCHESTRATION_SELF_UPDATE";
case UpdatesFailureReason::GET_UPDATE_REQUEST : return "GET_UPDATE_REQUEST";
case UpdatesFailureReason::DOWNLOAD_FILE : return "DOWNLOAD_FILE";
case UpdatesFailureReason::HANDLE_FILE : return "HANDLE_FILE";
case UpdatesFailureReason::INSTALLATION_QUEUE : return "INSTALLATION_QUEUE";
case UpdatesFailureReason::INSTALL_PACKAGE : return "INSTALL_PACKAGE";
case UpdatesFailureReason::CHECKSUM_UNMATCHED : return "CHECKSUM_UNMATCHED";
case UpdatesFailureReason::POLICY_CONFIGURATION : return "POLICY_CONFIGURATION";
case UpdatesFailureReason::POLICY_FOG_CONFIGURATION : return "POLICY_FOG_CONFIGURATION";
case UpdatesFailureReason::NONE : return "NONE";
}
dbgWarning(D_UPDATES_PROCESS_REPORTER) << "Trying to convert unknown updates failure reason to string.";
return "";
}
static inline std::string
convertUpdatesConfigTypeToStr(UpdatesConfigType type)
{
switch (type) {
case UpdatesConfigType::MANIFEST : return "MANIFEST";
case UpdatesConfigType::POLICY : return "POLICY";
case UpdatesConfigType::SETTINGS : return "SETTINGS";
case UpdatesConfigType::DATA : return "DATA";
case UpdatesConfigType::GENERAL : return "GENERAL";
}
dbgWarning(D_UPDATES_PROCESS_REPORTER) << "Trying to convert unknown updates failure reason to string.";
return "";
}
static inline std::string
convertUpdateProcessResultToStr(UpdatesProcessResult result)
{
switch (result) {
case UpdatesProcessResult::SUCCESS : return "SUCCESS";
case UpdatesProcessResult::UNSET : return "UNSET";
case UpdatesProcessResult::FAILED : return "FAILURE";
case UpdatesProcessResult::DEGRADED : return "DEGRADED";
}
dbgWarning(D_UPDATES_PROCESS_REPORTER) << "Trying to convert unknown updates failure reason to string.";
return "";
}
class UpdatesProcessEvent : public Event<UpdatesProcessEvent>
{
public:
UpdatesProcessEvent() {}
UpdatesProcessEvent(
UpdatesProcessResult _result,
UpdatesConfigType _type,
UpdatesFailureReason _reason = UpdatesFailureReason::NONE,
const std::string &_detail = "",
const std::string &_description = "");
~UpdatesProcessEvent() {}
UpdatesProcessResult getResult() const { return result; }
UpdatesConfigType getType() const { return type; }
UpdatesFailureReason getReason() const { return reason; }
std::string getDetail() const { return detail; }
std::string getDescription() const { return description; }
OrchestrationStatusFieldType getStatusFieldType() const;
OrchestrationStatusResult getOrchestrationStatusResult() const;
std::string parseDescription() const;
private:
UpdatesProcessResult result;
UpdatesConfigType type;
UpdatesFailureReason reason;
std::string detail;
std::string description;
};
#endif // __UPDATES_PROCESS_EVENT_H__

View File

@ -0,0 +1,61 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (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 __UPDATES_PROCESS_REPORT_H__
#define __UPDATES_PROCESS_REPORT_H__
#include <sstream>
#include <string>
#include "singleton.h"
#include "i_time_get.h"
#include "updates_process_event.h"
class UpdatesProcessReport : Singleton::Consume<I_TimeGet>
{
public:
UpdatesProcessReport(
UpdatesProcessResult result,
UpdatesConfigType type,
UpdatesFailureReason reason,
const std::string &description)
:
result(result), type(type), reason(reason), description(description)
{
time_stamp = Singleton::Consume<I_TimeGet>::by<UpdatesProcessReport>()->getWalltimeStr();
}
std::string
toString() const
{
std::stringstream report;
report
<< "["
<< time_stamp << "] - "
<< convertUpdateProcessResultToStr(result) << " | "
<< convertUpdatesConfigTypeToStr(type) << " | "
<< convertUpdatesFailureReasonToStr(reason) << " | "
<< description;
return report.str();
}
private:
UpdatesProcessResult result;
UpdatesConfigType type;
UpdatesFailureReason reason;
std::string description;
std::string time_stamp;
};
#endif // __UPDATES_PROCESS_EVENT_H__

View File

@ -0,0 +1,39 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (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 __UPDATES_PROCESS_REPORTER_H__
#define __UPDATES_PROCESS_REPORTER_H__
#include <string>
#include "event.h"
#include "singleton.h"
#include "config.h"
#include "debug.h"
#include "i_orchestration_status.h"
#include "health_check_status/health_check_status.h"
#include "updates_process_event.h"
#include "updates_process_report.h"
class UpdatesProcessReporter : public Listener<UpdatesProcessEvent>
{
public:
void upon(const UpdatesProcessEvent &event) override;
private:
void sendReoprt();
static std::vector<UpdatesProcessReport> reports;
};
#endif // __UPDATES_PROCESS_REPORTER_H__

View File

@ -21,6 +21,7 @@
#include "version.h"
#include "log_generator.h"
#include "orchestration_comp.h"
#include "updates_process_event.h"
using namespace std;
using namespace ReportIS;
@ -219,6 +220,13 @@ ManifestController::Impl::updateManifest(const string &new_manifest_file)
if (isIgnoreFile(new_manifest_file)) {
if (!orchestration_tools->copyFile(new_manifest_file, manifest_file_path)) {
dbgWarning(D_ORCHESTRATOR) << "Failed to copy a new manifest file";
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::MANIFEST,
UpdatesFailureReason::HANDLE_FILE,
new_manifest_file,
"Failed to copy a new manifest file"
).notify();
return false;
}
return true;
@ -237,6 +245,13 @@ ManifestController::Impl::updateManifest(const string &new_manifest_file)
if (!orchestration_tools->copyFile(new_manifest_file, manifest_file_path)) {
dbgWarning(D_ORCHESTRATOR) << "Failed to copy a new manifest file";
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::MANIFEST,
UpdatesFailureReason::HANDLE_FILE,
new_manifest_file,
"Failed to copy a new manifest file"
).notify();
return false;
}
return true;
@ -245,6 +260,13 @@ ManifestController::Impl::updateManifest(const string &new_manifest_file)
Maybe<map<string, Package>> parsed_manifest = orchestration_tools->loadPackagesFromJson(new_manifest_file);
if (!parsed_manifest.ok()) {
dbgWarning(D_ORCHESTRATOR) << "Failed to parse the new manifest file. File: " << new_manifest_file;
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::MANIFEST,
UpdatesFailureReason::HANDLE_FILE,
new_manifest_file,
"Failed to parse the new manifest file"
).notify();
return false;
}
@ -332,6 +354,13 @@ ManifestController::Impl::updateManifest(const string &new_manifest_file)
dbgWarning(D_ORCHESTRATOR)
<< "Failed building installation queue. Error: "
<< installation_queue_res.getErr();
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::MANIFEST,
UpdatesFailureReason::INSTALLATION_QUEUE,
"",
installation_queue_res.getErr()
).notify();
return false;
}
const vector<Package> &installation_queue = installation_queue_res.unpack();
@ -447,11 +476,25 @@ ManifestController::Impl::changeManifestFile(const string &new_manifest_file)
dbgDebug(D_ORCHESTRATOR) << "Writing new manifest to file";
if (!orchestration_tools->copyFile(new_manifest_file, manifest_file_path)) {
dbgWarning(D_ORCHESTRATOR) << "Failed write new manifest to file";
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::MANIFEST,
UpdatesFailureReason::HANDLE_FILE,
new_manifest_file,
"Failed write new manifest to file"
).notify();
return false;
}
if (!orchestration_tools->isNonEmptyFile(manifest_file_path)) {
dbgWarning(D_ORCHESTRATOR) << "Failed to get manifest file data";
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::MANIFEST,
UpdatesFailureReason::HANDLE_FILE,
manifest_file_path,
"Failed to get manifest file data"
).notify();
return false;
}

View File

@ -281,13 +281,7 @@ TEST_F(ManifestControllerTest, badChecksum)
EXPECT_CALL(mock_orchestration_tools, doesFileExist("/etc/cp/packages/my/my")).WillOnce(Return(false));
string hostname = "hostname";
string empty_err;
EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(empty_err));
EXPECT_CALL(mock_details_resolver, getHostname()).WillOnce(Return( Maybe<string>(hostname)));
EXPECT_CALL(
mock_status,
setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::FAILED, _)
);
EXPECT_FALSE(i_manifest_controller->updateManifest(file_name));
}
@ -710,10 +704,6 @@ TEST_F(ManifestControllerTest, selfUpdateWithOldCopyWithError)
string hostname = "hostname";
string empty_err;
EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(empty_err));
EXPECT_CALL(
mock_status,
setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::FAILED, _)
);
load(manifest, new_services);
EXPECT_CALL(mock_orchestration_tools,
@ -932,10 +922,6 @@ TEST_F(ManifestControllerTest, badInstall)
string empty_err;
EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(empty_err));
EXPECT_CALL(mock_details_resolver, getHostname()).WillOnce(Return( Maybe<string>(hostname)));
EXPECT_CALL(
mock_status,
setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::FAILED, _)
);
string corrupted_packages_manifest =
"{"
@ -1008,12 +994,6 @@ TEST_F(ManifestControllerTest, failToDownloadWithselfUpdate)
doesFileExist("/etc/cp/packages/orchestration/orchestration")
).WillOnce(Return(false));
EXPECT_CALL(mock_details_resolver, getHostname()).WillOnce(Return(string("hostname")));
EXPECT_CALL(
mock_status,
setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::FAILED, _)
);
string not_error;
EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(not_error));
EXPECT_FALSE(i_manifest_controller->updateManifest(file_name));
}
@ -1404,12 +1384,6 @@ TEST_F(ManifestControllerTest, failureOnDownloadSharedObject)
).WillOnce(Return(false));
EXPECT_CALL(mock_details_resolver, getHostname()).WillOnce(Return(string("hostname")));
EXPECT_CALL(mock_orchestration_tools, removeFile("/tmp/temp_file1")).WillOnce(Return(true));
EXPECT_CALL(
mock_status,
setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::FAILED, _)
);
string not_error;
EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(not_error));
EXPECT_FALSE(i_manifest_controller->updateManifest(file_name));
}
@ -2538,12 +2512,6 @@ TEST_F(ManifestDownloadTest, download_relative_path)
doesFileExist("/etc/cp/packages/orchestration/orchestration")
).WillOnce(Return(false));
EXPECT_CALL(mock_details_resolver, getHostname()).WillOnce(Return(string("hostname")));
EXPECT_CALL(
mock_status,
setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::FAILED, _)
);
string not_error;
EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(not_error));
EXPECT_FALSE(i_manifest_controller->updateManifest(manifest_file.fname));
}
@ -2589,8 +2557,6 @@ TEST_F(ManifestDownloadTest, download_relative_path_no_fog_domain)
mock_orchestration_tools,
doesFileExist("/etc/cp/packages/orchestration/orchestration")
).WillOnce(Return(false));
string not_error;
EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(not_error));
checkIfFileExistsCall(new_packages.at("orchestration"));
@ -2604,10 +2570,6 @@ TEST_F(ManifestDownloadTest, download_relative_path_no_fog_domain)
)
).WillOnce(Return(downloaded_package));
EXPECT_CALL(mock_details_resolver, getHostname()).WillOnce(Return(string("hostname")));
EXPECT_CALL(
mock_status,
setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::FAILED, _)
);
EXPECT_FALSE(i_manifest_controller->updateManifest(manifest_file.fname));
}

View File

@ -19,6 +19,7 @@
#include "config.h"
#include "agent_details.h"
#include "orchestration_comp.h"
#include "updates_process_event.h"
using namespace std;
@ -174,14 +175,13 @@ ManifestHandler::downloadPackages(const map<string, Package> &new_packages_to_do
" software update failed. Agent is running previous software. Contact Check Point support.";
}
auto orchestration_status = Singleton::Consume<I_OrchestrationStatus>::by<ManifestHandler>();
if (orchestration_status->getManifestError().find("Gateway was not fully deployed") == string::npos) {
orchestration_status->setFieldStatus(
OrchestrationStatusFieldType::MANIFEST,
OrchestrationStatusResult::FAILED,
install_error
);
}
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::MANIFEST,
UpdatesFailureReason::DOWNLOAD_FILE,
package.getName(),
install_error
).notify();
return genError(
"Failed to download installation package. Package: " +
package.getName() +
@ -219,11 +219,13 @@ ManifestHandler::installPackage(
err_hostname +
" software update failed. Agent is running previous software. Contact Check Point support.";
if (orchestration_status->getManifestError().find("Gateway was not fully deployed") == string::npos) {
orchestration_status->setFieldStatus(
OrchestrationStatusFieldType::MANIFEST,
OrchestrationStatusResult::FAILED,
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::MANIFEST,
UpdatesFailureReason::INSTALL_PACKAGE,
package_name,
install_error
);
).notify();
}
}
return self_update_status;
@ -289,11 +291,13 @@ ManifestHandler::installPackage(
auto orchestration_status = Singleton::Consume<I_OrchestrationStatus>::by<ManifestHandler>();
if (orchestration_status->getManifestError().find("Gateway was not fully deployed") == string::npos) {
orchestration_status->setFieldStatus(
OrchestrationStatusFieldType::MANIFEST,
OrchestrationStatusResult::FAILED,
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::MANIFEST,
UpdatesFailureReason::INSTALL_PACKAGE,
package_name,
install_error
);
).notify();
}
return false;
}

View File

@ -13,6 +13,7 @@
#include "mock/mock_agent_details.h"
#include "mock/mock_mainloop.h"
#include "mock/mock_rest_api.h"
#include "updates_process_event.h"
using namespace testing;
using namespace std;
@ -200,6 +201,19 @@ TEST_F(OrchestrationStatusTest, checkUpdateStatus)
auto result = orchestrationStatusFileToString();
EXPECT_EQ(buildOrchestrationStatusJSON("attempt time", "Succeeded ", "current time"), result);
}
TEST_F(OrchestrationStatusTest, checkUpdateStatusByRaiseEvent)
{
init();
EXPECT_CALL(time, getLocalTimeStr())
.WillOnce(Return(string("attempt time")))
.WillOnce(Return(string("current time")));
i_orchestration_status->setLastUpdateAttempt();
UpdatesProcessEvent(UpdatesProcessResult::SUCCESS, UpdatesConfigType::GENERAL).notify();
auto result = orchestrationStatusFileToString();
EXPECT_EQ(buildOrchestrationStatusJSON("attempt time", "Succeeded ", "current time"), result);
}
TEST_F(OrchestrationStatusTest, recoveryFields)
{
@ -482,3 +496,69 @@ TEST_F(OrchestrationStatusTest, setAllFields)
EXPECT_EQ(i_orchestration_status->getServiceSettings(), service_map_a);
EXPECT_EQ(i_orchestration_status->getRegistrationDetails(), agent_details);
}
TEST_F(OrchestrationStatusTest, checkErrorByRaiseEvent)
{
init();
string fog_address = "http://fog.address";
string registar_error = "Fail to registar";
string manifest_error = "Fail to achieve manifest";
string last_update_error = "Fail to update";
EXPECT_CALL(time, getLocalTimeStr()).Times(3).WillRepeatedly(Return(string("Time")));
UpdatesProcessEvent(UpdatesProcessResult::SUCCESS, UpdatesConfigType::GENERAL).notify();
i_orchestration_status->setIsConfigurationUpdated(
EnumArray<OrchestrationStatusConfigType, bool>(true, true, true)
);
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::GENERAL,
UpdatesFailureReason::NONE,
"",
last_update_error
).notify();
i_orchestration_status->setIsConfigurationUpdated(
EnumArray<OrchestrationStatusConfigType, bool>(false, false, false)
);
i_orchestration_status->setUpgradeMode("Online upgrades");
i_orchestration_status->setFogAddress(fog_address);
i_orchestration_status->setUpgradeMode("Online upgrades");
i_orchestration_status->setFogAddress(fog_address);
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::GENERAL,
UpdatesFailureReason::REGISTRATION,
"",
registar_error
).notify();
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::MANIFEST,
UpdatesFailureReason::NONE,
"",
manifest_error
).notify();
EXPECT_EQ(i_orchestration_status->getManifestError(), manifest_error);
auto result = orchestrationStatusFileToString();
EXPECT_EQ(
buildOrchestrationStatusJSON(
"None",
"Failed. Reason: " + last_update_error,
"Time",
"Time",
"",
"Time",
"Time",
"Online upgrades",
fog_address,
"Failed. Reason: Registration failed. Error: " + registar_error,
"Failed. Reason: " + manifest_error
),
result
);
}

View File

@ -19,6 +19,8 @@
#include "debug.h"
#include "config.h"
#include "updates_process_event.h"
#include "health_check_status/health_check_status.h"
using namespace cereal;
using namespace std;
@ -383,7 +385,10 @@ private:
map<string, string> service_settings;
};
class OrchestrationStatus::Impl : Singleton::Provide<I_OrchestrationStatus>::From<OrchestrationStatus>
class OrchestrationStatus::Impl
:
Singleton::Provide<I_OrchestrationStatus>::From<OrchestrationStatus>,
public Listener<UpdatesProcessEvent>
{
public:
void
@ -462,6 +467,13 @@ public:
},
"Write Orchestration status file"
);
registerListener();
}
void
upon(const UpdatesProcessEvent &event) override
{
setFieldStatus(event.getStatusFieldType(), event.getOrchestrationStatusResult(), event.parseDescription());
}
private:

View File

@ -42,6 +42,8 @@
#include "hybrid_communication.h"
#include "agent_core_utilities.h"
#include "fog_communication.h"
#include "updates_process_event.h"
#include "updates_process_reporter.h"
using namespace std;
using namespace chrono;
@ -53,85 +55,6 @@ USE_DEBUG_FLAG(D_ORCHESTRATOR);
static string fw_last_update_time = "";
#endif // gaia || smb
class HealthCheckStatusListener : public Listener<HealthCheckStatusEvent>
{
public:
void upon(const HealthCheckStatusEvent &) override {}
HealthCheckStatusReply
respond(const HealthCheckStatusEvent &) override
{
return HealthCheckStatusReply(comp_name, status, extended_status);
}
string getListenerName() const override { return "HealthCheckStatusListener"; }
void
setStatus(
HealthCheckStatus _status,
OrchestrationStatusFieldType _status_field_type,
const string &_status_description = "Success")
{
string status_field_type_str = convertOrchestrationStatusFieldTypeToStr(_status_field_type);
extended_status[status_field_type_str] = _status_description;
field_types_status[status_field_type_str] = _status;
switch(_status) {
case HealthCheckStatus::UNHEALTHY: {
status = HealthCheckStatus::UNHEALTHY;
return;
}
case HealthCheckStatus::DEGRADED: {
for (const auto &type_status : field_types_status) {
if ((type_status.first != status_field_type_str)
&& (type_status.second == HealthCheckStatus::UNHEALTHY))
{
return;
}
}
status = HealthCheckStatus::DEGRADED;
return;
}
case HealthCheckStatus::HEALTHY: {
for (const auto &type_status : field_types_status) {
if ((type_status.first != status_field_type_str)
&& (type_status.second == HealthCheckStatus::UNHEALTHY
|| type_status.second == HealthCheckStatus::DEGRADED)
)
{
return;
}
status = HealthCheckStatus::HEALTHY;
}
return;
}
case HealthCheckStatus::IGNORED: {
return;
}
}
}
private:
string
convertOrchestrationStatusFieldTypeToStr(OrchestrationStatusFieldType type)
{
switch (type) {
case OrchestrationStatusFieldType::REGISTRATION : return "Registration";
case OrchestrationStatusFieldType::MANIFEST : return "Manifest";
case OrchestrationStatusFieldType::LAST_UPDATE : return "Last Update";
case OrchestrationStatusFieldType::COUNT : return "Count";
}
dbgError(D_ORCHESTRATOR) << "Trying to convert unknown orchestration status field to string.";
return "";
}
string comp_name = "Orchestration";
HealthCheckStatus status = HealthCheckStatus::IGNORED;
map<string, string> extended_status;
map<string, HealthCheckStatus> field_types_status;
};
class SetAgentUninstall
:
public ServerRest,
@ -257,6 +180,13 @@ private:
<< "Failed to load Orchestration Policy. Error: "
<< maybe_policy.getErr()
<< "Trying to load from backup.";
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::POLICY,
UpdatesFailureReason::POLICY_CONFIGURATION,
orchestration_policy_file,
maybe_policy.getErr()
).notify();
return loadOrchestrationPolicyFromBackup();
}
@ -280,6 +210,13 @@ private:
return maybe_policy;
}
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::POLICY,
UpdatesFailureReason::POLICY_CONFIGURATION,
orchestration_policy_file + backup_ext,
maybe_policy.getErr()
).notify();
return genError("Failed to load Orchestration policy from backup.");
}
@ -337,17 +274,13 @@ private:
<< new_manifest_file.getErr()
<< " Presenting the next message to the user: "
<< install_error;
i_orchestration_status->setFieldStatus(
OrchestrationStatusFieldType::MANIFEST,
OrchestrationStatusResult::FAILED,
install_error
);
health_check_status_listener.setStatus(
HealthCheckStatus::UNHEALTHY,
OrchestrationStatusFieldType::MANIFEST,
install_error
);
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::MANIFEST,
UpdatesFailureReason::DOWNLOAD_FILE,
resource_file.getFileName(),
new_manifest_file.getErr()
).notify();
return genError(install_error);
}
@ -372,23 +305,12 @@ private:
<< "Manifest failed to be updated. Presenting the next message to the user: "
<< install_error;
health_check_status_listener.setStatus(
HealthCheckStatus::UNHEALTHY,
OrchestrationStatusFieldType::MANIFEST,
install_error
);
return genError(install_error);
}
i_orchestration_status->setFieldStatus(
OrchestrationStatusFieldType::MANIFEST,
OrchestrationStatusResult::SUCCESS
);
health_check_status_listener.setStatus(
HealthCheckStatus::HEALTHY,
OrchestrationStatusFieldType::MANIFEST
);
UpdatesProcessEvent(
UpdatesProcessResult::SUCCESS,
UpdatesConfigType::MANIFEST
).notify();
ifstream restart_watchdog_orch(filesystem_prefix + "/orchestration/restart_watchdog");
if (restart_watchdog_orch.good()) {
@ -473,6 +395,13 @@ private:
if (!updateFogAddress(policy.getFogAddress())) {
dbgWarning(D_ORCHESTRATOR) << "Failed to restore the old Fog address.";
}
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::POLICY,
UpdatesFailureReason::POLICY_FOG_CONFIGURATION,
orchestration_policy.getFogAddress(),
"Failed to update the new Fog address."
).notify();
return "";
}
@ -499,13 +428,19 @@ private:
// Handling policy update.
dbgInfo(D_ORCHESTRATOR) << "There is a new policy file.";
GetResourceFile resource_file(GetResourceFile::ResourceFileType::POLICY);
Maybe<string> new_policy_file =
Singleton::Consume<I_Downloader>::by<OrchestrationComp>()->downloadFile(
Maybe<string> new_policy_file = Singleton::Consume<I_Downloader>::by<OrchestrationComp>()->downloadFile(
new_policy.unpack(),
I_OrchestrationTools::SELECTED_CHECKSUM_TYPE,
resource_file
);
if (!new_policy_file.ok()) {
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::POLICY,
UpdatesFailureReason::DOWNLOAD_FILE,
resource_file.getFileName(),
new_policy_file.getErr()
).notify();
return genError("Failed to download the new policy file. Error: " + new_policy_file.getErr());
}
@ -564,6 +499,13 @@ private:
<< LogField("policyVersion", updated_policy_version)
<< LogField("previousPolicyVersion", old_policy_version);
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::POLICY,
UpdatesFailureReason::POLICY_CONFIGURATION,
updated_policy_version,
res.getErr()
).notify();
return genError(error_str);
}
i_service_controller->moveChangedPolicies();
@ -648,6 +590,11 @@ private:
"Send policy update report"
);
UpdatesProcessEvent(
UpdatesProcessResult::SUCCESS,
UpdatesConfigType::POLICY
).notify();
dbgInfo(D_ORCHESTRATOR) << "Policy update report was successfully sent to fog";
return Maybe<void>();
@ -683,10 +630,24 @@ private:
);
if (!new_data_files.ok()) {
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::DATA,
UpdatesFailureReason::DOWNLOAD_FILE,
resource_file.getFileName(),
new_data_files.getErr()
).notify();
return genError("Failed to download new data file, Error: " + new_data_files.getErr());
}
auto new_data_file_input = i_orchestration_tools->readFile(new_data_files.unpack());
if (!new_data_file_input.ok()) {
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::DATA,
UpdatesFailureReason::HANDLE_FILE,
resource_file.getFileName(),
"Failed to read new data file, Error: " + new_data_file_input.getErr()
).notify();
return genError("Failed to read new data file, Error: " + new_data_file_input.getErr());
}
@ -702,21 +663,35 @@ private:
<< e.what()
<< ". Content: "
<< new_data_files.unpack();
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::DATA,
UpdatesFailureReason::HANDLE_FILE,
new_data_files.unpack(),
string("Failed to load data from JSON file, Error: ") + e.what()
).notify();
return genError(e.what());
}
for (const auto &data_file : parsed_data) {
const string data_file_save_path = getPolicyConfigPath(data_file.first, Config::ConfigFileType::Data);
Maybe<string> new_data_file =
Singleton::Consume<I_Downloader>::by<OrchestrationComp>()->downloadFileFromURL(
data_file.second.getDownloadPath(),
data_file.second.getChecksum(),
I_OrchestrationTools::SELECTED_CHECKSUM_TYPE,
"data_" + data_file.first
);
Singleton::Consume<I_Downloader>::by<OrchestrationComp>()->downloadFileFromURL(
data_file.second.getDownloadPath(),
data_file.second.getChecksum(),
I_OrchestrationTools::SELECTED_CHECKSUM_TYPE,
"data_" + data_file.first
);
if (!new_data_file.ok()) {
dbgWarning(D_ORCHESTRATOR) << "Failed to download the " << data_file.first << " data file.";
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::DATA,
UpdatesFailureReason::DOWNLOAD_FILE,
data_file.first,
new_data_file.getErr()
).notify();
return new_data_file.passErr();
}
auto data_new_checksum = getChecksum(new_data_file.unpack());
@ -729,6 +704,16 @@ private:
<< data_new_checksum;
dbgWarning(D_ORCHESTRATOR) << current_error.str();
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::DATA,
UpdatesFailureReason::CHECKSUM_UNMATCHED,
data_file.first,
" Expected checksum: " +
data_file.second.getChecksum() +
". Downloaded checksum: " +
data_new_checksum
).notify();
return genError(current_error.str());
}
if (!i_orchestration_tools->copyFile(new_data_file.unpack(), data_file_save_path)) {
@ -741,6 +726,10 @@ private:
dbgWarning(D_ORCHESTRATOR) << "Failed to copy a new agents' data file to " << data_file_path;
}
UpdatesProcessEvent(
UpdatesProcessResult::SUCCESS,
UpdatesConfigType::DATA
).notify();
return Maybe<void>();
}
@ -751,8 +740,7 @@ private:
dbgInfo(D_ORCHESTRATOR) << "There is a new settings file.";
GetResourceFile resource_file(GetResourceFile::ResourceFileType::SETTINGS);
Maybe<string> new_settings_file =
Singleton::Consume<I_Downloader>::by<OrchestrationComp>()->downloadFile(
Maybe<string> new_settings_file = Singleton::Consume<I_Downloader>::by<OrchestrationComp>()->downloadFile(
orch_settings.unpack(),
I_OrchestrationTools::SELECTED_CHECKSUM_TYPE,
resource_file
@ -762,6 +750,13 @@ private:
dbgWarning(D_ORCHESTRATOR)
<< "Failed to download the new settings file. Error: "
<< new_settings_file.getErr();
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::SETTINGS,
UpdatesFailureReason::DOWNLOAD_FILE,
resource_file.getFileName(),
new_settings_file.getErr()
).notify();
return genError("Failed to download the new settings file. Error: " + new_settings_file.getErr());
}
@ -769,6 +764,10 @@ private:
if (res.ok()) {
settings_file_path = *res;
reloadConfiguration();
UpdatesProcessEvent(
UpdatesProcessResult::SUCCESS,
UpdatesConfigType::SETTINGS
).notify();
return Maybe<void>();
}
@ -877,11 +876,13 @@ private:
if (!response.ok()) {
dbgWarning(D_ORCHESTRATOR) << "Failed to get the update. Error: " << response.getErr();
i_orchestration_status->setFieldStatus(
OrchestrationStatusFieldType::LAST_UPDATE,
OrchestrationStatusResult::FAILED,
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::GENERAL,
UpdatesFailureReason::GET_UPDATE_REQUEST,
"",
"Warning: Agent/Gateway failed during the update process. Contact Check Point support."
);
).notify();
return genError(response.getErr());
}
@ -924,10 +925,10 @@ private:
OrchSettings orch_settings = response.getSettings();
OrchData orch_data = response.getData();
i_orchestration_status->setFieldStatus(
OrchestrationStatusFieldType::LAST_UPDATE,
OrchestrationStatusResult::SUCCESS
);
UpdatesProcessEvent(
UpdatesProcessResult::SUCCESS,
UpdatesConfigType::GENERAL
).notify();
i_orchestration_status->setIsConfigurationUpdated(
EnumArray<OrchestrationStatusConfigType, bool>(
orch_manifest.ok(), orch_policy.ok(), orch_settings.ok(), orch_data.ok()
@ -1017,6 +1018,10 @@ private:
}
if (maybe_errors != "") return genError(maybe_errors);
UpdatesProcessEvent(
UpdatesProcessResult::SUCCESS,
UpdatesConfigType::GENERAL
).notify();
return Maybe<void>();
}
@ -1196,6 +1201,13 @@ private:
dbgTrace(D_ORCHESTRATOR) << "The settings directory is " << settings_file_path;
if (!i_orchestration_tools->copyFile(new_settings_file, settings_file_path)) {
dbgWarning(D_ORCHESTRATOR) << "Failed to update the settings.";
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::SETTINGS,
UpdatesFailureReason::HANDLE_FILE,
settings_file_path,
"Failed to update the settings"
).notify();
return genError("Failed to update the settings");
}
@ -1303,6 +1315,8 @@ private:
report << make_pair("cloudAccountId", ::get<0>(cloud_metadata.unpack()));
report << make_pair("cloudVpcId", ::get<1>(cloud_metadata.unpack()));
report << make_pair("cloudInstanceId", ::get<2>(cloud_metadata.unpack()));
report << make_pair("cloudInstanceLocalIp", ::get<3>(cloud_metadata.unpack()));
report << make_pair("cloudRegion", ::get<4>(cloud_metadata.unpack()));
}
void
@ -1443,20 +1457,24 @@ private:
<< check_update_result.getErr()
<< ", new check will be every: "
<< sleep_interval << " seconds";
health_check_status_listener.setStatus(
HealthCheckStatus::UNHEALTHY,
OrchestrationStatusFieldType::LAST_UPDATE,
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::GENERAL,
UpdatesFailureReason::CHECK_UPDATE,
"",
"Failed during check update. Error: " + check_update_result.getErr()
);
).notify();
return;
}
failure_count = 0;
dbgDebug(D_ORCHESTRATOR) << "Check update process completed successfully";
health_check_status_listener.setStatus(
HealthCheckStatus::HEALTHY,
OrchestrationStatusFieldType::LAST_UPDATE
);
UpdatesProcessEvent(
UpdatesProcessResult::SUCCESS,
UpdatesConfigType::GENERAL,
UpdatesFailureReason::CHECK_UPDATE,
"",
"Check update procces succeeded!"
).notify();
sleep_interval = policy.getSleepInterval();
if (!is_new_success) {
dbgInfo(D_ORCHESTRATOR)
@ -1491,11 +1509,13 @@ private:
sleep_interval = policy.getErrorSleepInterval();
Maybe<void> registration_status(genError("Not running yet."));
while (!(registration_status = registerToTheFog()).ok()) {
health_check_status_listener.setStatus(
HealthCheckStatus::UNHEALTHY,
OrchestrationStatusFieldType::REGISTRATION,
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::GENERAL,
UpdatesFailureReason::REGISTRATION,
"",
registration_status.getErr()
);
).notify();
sleep_interval = getConfigurationWithDefault<int>(
30,
"orchestration",
@ -1515,10 +1535,11 @@ private:
Singleton::Consume<I_MainLoop>::by<OrchestrationComp>()->yield(chrono::seconds(1));
health_check_status_listener.setStatus(
HealthCheckStatus::HEALTHY,
OrchestrationStatusFieldType::REGISTRATION
);
UpdatesProcessEvent(
UpdatesProcessResult::SUCCESS,
UpdatesConfigType::GENERAL,
UpdatesFailureReason::REGISTRATION
).notify();
LogGen(
"Check Point Orchestration nano service successfully started",
@ -1552,16 +1573,18 @@ private:
if (!Singleton::Consume<I_ManifestController>::by<OrchestrationComp>()->loadAfterSelfUpdate()) {
// Should restore from backup
dbgWarning(D_ORCHESTRATOR) << "Failed to load Orchestration after self-update";
health_check_status_listener.setStatus(
HealthCheckStatus::UNHEALTHY,
OrchestrationStatusFieldType::LAST_UPDATE,
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::GENERAL,
UpdatesFailureReason::ORCHESTRATION_SELF_UPDATE,
"",
"Failed to load Orchestration after self-update"
);
).notify();
} else {
health_check_status_listener.setStatus(
HealthCheckStatus::HEALTHY,
OrchestrationStatusFieldType::MANIFEST
);
UpdatesProcessEvent(
UpdatesProcessResult::SUCCESS,
UpdatesConfigType::MANIFEST
).notify();
}
setUpgradeTime();
@ -1911,7 +1934,7 @@ private:
ReportIS::Audience::INTERNAL
);
hybrid_mode_metric.registerListener();
health_check_status_listener.registerListener();
updates_process_reporter_listener.registerListener();
}
void
@ -2024,7 +2047,7 @@ private:
unsigned int sleep_interval = 0;
bool is_new_success = false;
OrchestrationPolicy policy;
HealthCheckStatusListener health_check_status_listener;
UpdatesProcessReporter updates_process_reporter_listener;
HybridModeMetric hybrid_mode_metric;
EnvDetails env_details;
chrono::minutes upgrade_delay_time;

View File

@ -20,6 +20,7 @@
#include "cereal/types/set.hpp"
#include "agent_core_utilities.h"
#include "namespace_data.h"
#include "updates_process_event.h"
#include <netdb.h>
#include <arpa/inet.h>
@ -469,6 +470,13 @@ OrchestrationTools::Impl::packagesToJsonFile(const map<packageName, Package> &pa
archive_out(cereal::make_nvp("packages", packges_vector));
} catch (cereal::Exception &e) {
dbgDebug(D_ORCHESTRATOR) << "Failed to write vector of packages to JSON file " << path << ", " << e.what();
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::MANIFEST,
UpdatesFailureReason::HANDLE_FILE,
path,
string("Failed to write vector of packages to JSON file. Error: ") + e.what()
).notify();
return false;
}
return true;

View File

@ -144,7 +144,7 @@ public:
map<string, string> resolved_mgmt_details({{"kernel_version", "4.4.0-87-generic"}});
EXPECT_CALL(mock_details_resolver, getResolvedDetails()).WillRepeatedly(Return(resolved_mgmt_details));
EXPECT_CALL(mock_details_resolver, readCloudMetadata()).WillRepeatedly(
Return(Maybe<tuple<string, string, string>>(genError("No cloud metadata")))
Return(Maybe<tuple<string, string, string, string, string>>(genError("No cloud metadata")))
);
}
@ -284,7 +284,7 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource)
EXPECT_CALL(mock_service_controller, getPolicyVersion())
.Times(3).WillRepeatedly(ReturnRef(first_policy_version));
map<string, PortNumber> empty_service_to_port_map;
map<string, vector<PortNumber>> empty_service_to_port_map;
EXPECT_CALL(mock_service_controller, getServiceToPortMap()).WillRepeatedly(Return(empty_service_to_port_map));

View File

@ -22,6 +22,7 @@
#include "agent_details.h"
#include "customized_cereal_map.h"
#include "health_check_status/health_check_status.h"
#include "updates_process_event.h"
#include "declarative_policy_utils.h"
using namespace testing;
@ -99,7 +100,7 @@ public:
)
);
map<string, PortNumber> empty_service_to_port_map;
map<string, vector<PortNumber>> empty_service_to_port_map;
EXPECT_CALL(mock_service_controller, getServiceToPortMap()).WillRepeatedly(Return(empty_service_to_port_map));
EXPECT_CALL(rest, mockRestCall(RestAction::SHOW, "orchestration-status", _)).WillOnce(
@ -171,7 +172,7 @@ public:
map<string, string> resolved_mgmt_details({{"kernel_version", "4.4.0-87-generic"}});
EXPECT_CALL(mock_details_resolver, getResolvedDetails()).WillRepeatedly(Return(resolved_mgmt_details));
EXPECT_CALL(mock_details_resolver, readCloudMetadata()).WillRepeatedly(
Return(Maybe<tuple<string, string, string>>(genError("No cloud metadata")))
Return(Maybe<tuple<string, string, string, string, string>>(genError("No cloud metadata")))
);
}
@ -358,6 +359,7 @@ private:
TEST_F(OrchestrationTest, hybridModeRegisterLocalAgentRoutine)
{
EXPECT_CALL(rest, mockRestCall(_, _, _)).WillRepeatedly(Return(true));
Singleton::Consume<Config::I_Config>::from(config_comp)->loadConfiguration(
vector<string>{"--orchestration-mode=hybrid_mode"}
);
@ -376,7 +378,6 @@ TEST_F(OrchestrationTest, hybridModeRegisterLocalAgentRoutine)
expectDetailsResolver();
EXPECT_CALL(mock_update_communication, getUpdate(_));
EXPECT_CALL(mock_status, setLastUpdateAttempt());
EXPECT_CALL(mock_status, setFieldStatus(_, _, _));
EXPECT_CALL(mock_status, setIsConfigurationUpdated(_));
EXPECT_CALL(mock_ml, yield(A<chrono::microseconds>()))
@ -584,7 +585,6 @@ TEST_F(OrchestrationTest, check_sending_registration_data)
expectDetailsResolver();
EXPECT_CALL(mock_update_communication, getUpdate(_));
EXPECT_CALL(mock_status, setLastUpdateAttempt());
EXPECT_CALL(mock_status, setFieldStatus(_, _, _));
EXPECT_CALL(mock_status, setIsConfigurationUpdated(_));
EXPECT_CALL(mock_ml, yield(A<chrono::microseconds>()))
@ -761,10 +761,6 @@ TEST_F(OrchestrationTest, orchestrationPolicyUpdatRollback)
).WillOnce(Return(true));
EXPECT_CALL(mock_update_communication, setAddressExtenesion("/test"));
EXPECT_CALL(mock_status, setLastUpdateAttempt());
EXPECT_CALL(
mock_status,
setFieldStatus(OrchestrationStatusFieldType::LAST_UPDATE, OrchestrationStatusResult::SUCCESS, "")
);
EXPECT_CALL(mock_status, setIsConfigurationUpdated(A<EnumArray<OrchestrationStatusConfigType, bool>>())
).WillOnce(
Invoke(
@ -940,10 +936,6 @@ TEST_F(OrchestrationTest, orchestrationPolicyUpdate)
).WillOnce(Return(true));
EXPECT_CALL(mock_update_communication, setAddressExtenesion("/test"));
EXPECT_CALL(mock_status, setLastUpdateAttempt());
EXPECT_CALL(
mock_status,
setFieldStatus(OrchestrationStatusFieldType::LAST_UPDATE, OrchestrationStatusResult::SUCCESS, "")
);
EXPECT_CALL(mock_status, setIsConfigurationUpdated(A<EnumArray<OrchestrationStatusConfigType, bool>>())
).WillOnce(
Invoke(
@ -1013,7 +1005,7 @@ TEST_F(OrchestrationTest, loadOrchestrationPolicyFromBackup)
)
);
map<string, PortNumber> empty_service_to_port_map;
map<string, vector<PortNumber>> empty_service_to_port_map;
EXPECT_CALL(mock_service_controller, getServiceToPortMap()).WillRepeatedly(Return(empty_service_to_port_map));
EXPECT_CALL(rest, mockRestCall(RestAction::SHOW, "orchestration-status", _));
@ -1108,14 +1100,6 @@ TEST_F(OrchestrationTest, manifestUpdate)
);
EXPECT_CALL(mock_status, setLastUpdateAttempt());
EXPECT_CALL(
mock_status,
setFieldStatus(OrchestrationStatusFieldType::LAST_UPDATE, OrchestrationStatusResult::SUCCESS, "")
);
EXPECT_CALL(
mock_status,
setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::SUCCESS, "")
);
EXPECT_CALL(mock_status, setIsConfigurationUpdated(A<EnumArray<OrchestrationStatusConfigType, bool>>())
).WillOnce(
Invoke(
@ -1237,10 +1221,6 @@ TEST_F(OrchestrationTest, getBadPolicyUpdate)
.WillOnce(ReturnRef(second_val)
);
EXPECT_CALL(mock_status, setLastUpdateAttempt());
EXPECT_CALL(
mock_status,
setFieldStatus(OrchestrationStatusFieldType::LAST_UPDATE, OrchestrationStatusResult::SUCCESS, "")
);
EXPECT_CALL(mock_status, setIsConfigurationUpdated(A<EnumArray<OrchestrationStatusConfigType, bool>>())
).WillOnce(
Invoke(
@ -1271,7 +1251,7 @@ TEST_F(OrchestrationTest, getBadPolicyUpdate)
EXPECT_CALL(
mock_service_controller,
updateServiceConfiguration(string("policy path"), "", expected_data_types, "", "", _)
).WillOnce(Return(Maybe<void>(genError(string("")))));
).WillOnce(Return(Maybe<void>(genError(string("Fail to load policy")))));
EXPECT_CALL(mock_ml, yield(A<chrono::microseconds>()))
.WillOnce(
@ -1328,6 +1308,7 @@ TEST_F(OrchestrationTest, failedDownloadSettings)
EXPECT_CALL(mock_update_communication, authenticateAgent()).WillOnce(Return(Maybe<void>()));
expectDetailsResolver();
EXPECT_CALL(mock_manifest_controller, loadAfterSelfUpdate()).WillOnce(Return(false));
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::SHA256, manifest_file_path))
.WillOnce(Return(manifest_checksum));
@ -1359,22 +1340,10 @@ TEST_F(OrchestrationTest, failedDownloadSettings)
);
EXPECT_CALL(mock_status, setLastUpdateAttempt());
EXPECT_CALL(
mock_status,
setFieldStatus(OrchestrationStatusFieldType::LAST_UPDATE, OrchestrationStatusResult::SUCCESS, "")
).Times(1);
string manifest_err =
"Critical Error: Agent/Gateway was not fully deployed on host 'hostname' "
"and is not enforcing a security policy. Retry installation or contact Check Point support.";
EXPECT_CALL(
mock_status,
setFieldStatus(
OrchestrationStatusFieldType::MANIFEST,
OrchestrationStatusResult::FAILED,
manifest_err
)
).Times(1);
EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(manifest_err));
EXPECT_CALL(mock_status, setIsConfigurationUpdated(A<EnumArray<OrchestrationStatusConfigType, bool>>())
@ -1475,10 +1444,6 @@ TEST_P(OrchestrationTest, orchestrationFirstRun)
.WillOnce(Return(data_checksum));
EXPECT_CALL(mock_status, setLastUpdateAttempt());
EXPECT_CALL(
mock_status,
setFieldStatus(OrchestrationStatusFieldType::LAST_UPDATE, OrchestrationStatusResult::SUCCESS, "")
);
EXPECT_CALL(mock_status, setIsConfigurationUpdated(A<EnumArray<OrchestrationStatusConfigType, bool>>())
).WillOnce(
Invoke(
@ -1537,23 +1502,6 @@ TEST_P(OrchestrationTest, orchestrationFirstRun)
} catch (const invalid_argument& e) {}
EXPECT_CALL(mock_status, writeStatusToFile());
vector<HealthCheckStatusReply> reply;
bool is_named_query = GetParam();
if (is_named_query) {
auto all_comps_status_reply = HealthCheckStatusEvent().performNamedQuery();
for (auto &elem : all_comps_status_reply) {
reply.push_back(elem.second);
}
} else {
reply = HealthCheckStatusEvent().query();
}
ASSERT_EQ(reply.size(), 1);
EXPECT_EQ(reply[0].getCompName(), "Orchestration");
EXPECT_EQ(reply[0].getStatus(), HealthCheckStatus::HEALTHY);
HealthCheckStatusEvent().notify();
orchestration_comp.fini();
}
@ -1721,10 +1669,6 @@ TEST_F(OrchestrationTest, dataUpdate)
);
EXPECT_CALL(mock_status, setLastUpdateAttempt());
EXPECT_CALL(
mock_status,
setFieldStatus(OrchestrationStatusFieldType::LAST_UPDATE, OrchestrationStatusResult::SUCCESS, "")
);
EXPECT_CALL(mock_status, setIsConfigurationUpdated(A<EnumArray<OrchestrationStatusConfigType, bool>>())
).WillOnce(
Invoke(

View File

@ -333,7 +333,7 @@ private:
ReconfStatus getUpdatedReconfStatus();
Maybe<ServiceDetails> getServiceDetails(const string &service_name);
map<string, PortNumber> getServiceToPortMap();
map<string, vector<PortNumber>> getServiceToPortMap();
template<class Archive>
void serializeRegisterServices(Archive &ar) { ar(pending_services); }
@ -358,6 +358,7 @@ private:
string filesystem_prefix;
bool is_multi_tenant_env = false;
set<string> changed_policy_files;
ServiceDetails orchestration_service_details;
I_OrchestrationTools *orchestration_tools = nullptr;
I_MainLoop *mainloop = nullptr;
@ -374,8 +375,13 @@ public:
for (auto const& entry: ports_map) {
string service = entry.first;
replace(service.begin(), service.end(), ' ', '-');
output << service << ":";
output << entry.second << ",";
output << service;
char delim = ':';
for (PortNumber port : entry.second) {
output << delim << port;
delim = ',';
}
output << ";";
}
ports_list = output.str();
}
@ -500,6 +506,7 @@ ServiceController::Impl::loadRegisteredServicesFromFile()
stringstream ss(maybe_registered_services_str.unpack());
cereal::JSONInputArchive ar(ss);
ar(cereal::make_nvp("Registered Services", pending_services));
pending_services.erase("cp-nano-orchestration");
dbgInfo(D_SERVICE_CONTROLLER)
<< "Orchestration pending services loaded from file."
@ -529,16 +536,24 @@ ServiceController::Impl::writeRegisteredServicesToFile()
"Orchestration registered services"
);
map<string, ServiceDetails> registered_services_with_orch = registered_services;
if (orchestration_service_details.getServiceID() != "") {
registered_services_with_orch.emplace(
orchestration_service_details.getServiceID(),
orchestration_service_details
);
}
ofstream ss(registered_services_file);
cereal::JSONOutputArchive ar(ss);
ar(cereal::make_nvp("Registered Services", registered_services));
ar(cereal::make_nvp("Registered Services", registered_services_with_orch));
dbgInfo(D_SERVICE_CONTROLLER)
<< "Orchestration registered services file has been updated. File: "
<< registered_services_file
<< ". Registered Services:";
for (const auto &id_service_pair : registered_services) {
for (const auto &id_service_pair : registered_services_with_orch) {
const auto &service = id_service_pair.second;
dbgInfo(D_SERVICE_CONTROLLER)
<< "Service name: "
@ -591,20 +606,20 @@ ServiceController::Impl::cleanUpVirtualFiles()
}
}
map<string, PortNumber>
map<string, vector<PortNumber>>
ServiceController::Impl::getServiceToPortMap()
{
map<string, PortNumber> ports_map;
map<string, vector<PortNumber>> ports_map;
for (auto const& entry: registered_services) {
const string &service = entry.first;
const string &service = entry.second.getServiceName();
PortNumber port = entry.second.getPort();
ports_map[service] = port;
ports_map[service].push_back(port);
}
for (auto const& entry: pending_services) {
const string &service = entry.first;
const string &service = entry.second.getServiceName();
PortNumber port = entry.second.getPort();
ports_map[service] = port;
ports_map[service].push_back(port);
}
return ports_map;
@ -624,6 +639,12 @@ ServiceController::Impl::registerServiceConfig(
service_id
);
if (service_name == "cp-nano-orchestration") {
dbgTrace(D_SERVICE_CONTROLLER) << "Save the orchestration service details";
orchestration_service_details = service_config;
return;
}
pending_services.erase(service_config.getServiceID());
pending_services.insert({service_config.getServiceID(), service_config});
refreshPendingServices();

View File

@ -178,16 +178,17 @@ public:
void
expectNewConfigRequest(const string &response)
{
Maybe<HTTPResponse, HTTPResponse> res = HTTPResponse(HTTPStatusCode::HTTP_OK, response);
EXPECT_CALL(
mock_message,
sendSyncMessage(
HTTPMethod::POST,
"/set-new-configuration",
HasSubstr("1.0.2"),
_,
_,
_
)
).WillOnce(Return(HTTPResponse(HTTPStatusCode::HTTP_OK, response)));
).WillOnce(DoAll(SaveArg<2>(&version_body), Return(res)));
}
CPTestTempfile status_file;
@ -196,6 +197,7 @@ public:
::Environment env;
ConfigComponent config;
DeclarativePolicyUtils declarative_policy_utils;
string version_body;
string configuration_dir;
string policy_extension;
string settings_extension;
@ -229,19 +231,21 @@ public:
string old_version = "1.0.1";
string versions =
"["
" {"
" \"id\": \"d8c3cc3c-f9df-83c8-f875-322dd8a0c161\","
" \"name\": \"Linux Embedded Agents\","
" \"version\": \"1.0.2\""
" }"
"[\n"
" {\n"
" \"id\": \"d8c3cc3c-f9df-83c8-f875-322dd8a0c161\",\n"
" \"name\": \"Linux Embedded Agents\",\n"
" \"version\": \"1.0.2\",\n"
" \"profileType\": \"Embedded\"\n"
" }\n"
"]";
string old_versions =
"["
" {"
" \"id\": \"d8c3cc3c-f9df-83c8-f875-322dd8a0c161\","
" \"name\": \"Linux Embedded Agents\","
" \"version\": \"1.0.1\""
" \"version\": \"1.0.1\","
" \"profileType\": \"Embedded\""
" }"
"]";
@ -338,6 +342,23 @@ TEST_F(ServiceControllerTest, UpdateConfiguration)
EXPECT_EQ(i_service_controller->getPolicyVersion(), version_value);
EXPECT_EQ(i_service_controller->getPolicyVersions(), versions);
EXPECT_EQ(i_service_controller->getUpdatePolicyVersion(), version_value);
stringstream ver_ss;
ver_ss
<< "{\n"
<< " \"id\": 1,\n"
<< " \"policy_version\": \"1.0.2,[\\n"
<< " {\\n"
<< " \\\"id\\\": \\\"d8c3cc3c-f9df-83c8-f875-322dd8a0c161\\\",\\n"
<< " \\\"name\\\": \\\"Linux Embedded Agents\\\",\\n"
<< " \\\"version\\\": \\\"1.0.2\\\",\\n"
<< " \\\"profileType\\\": \\\"Embedded\\\"\\n"
<< " }\\n"
<< "]\"\n}";
EXPECT_EQ(
version_body,
ver_ss.str()
);
}
TEST_F(ServiceControllerTest, supportVersions)
@ -527,13 +548,13 @@ TEST_F(ServiceControllerTest, TimeOutUpdateConfiguration)
TEST_F(ServiceControllerTest, readRegisteredServicesFromFile)
{
init();
int family1_id3_port = 1111;
uint16_t family1_id3_port = 1111;
string registered_services_json = "{\n"
" \"Registered Services\": {\n"
" \"family1_id3\": {\n"
" \"Service name\": \"mock access control\",\n"
" \"Service ID\": \"family1_id3\",\n"
" \"Service port\": 1111,\n"
" \"Service port\": " + to_string(family1_id3_port) + ",\n"
" \"Relevant configs\": [\n"
" \"non updated capability\",\n"
" \"l4_firewall\"\n"
@ -573,7 +594,8 @@ TEST_F(ServiceControllerTest, readRegisteredServicesFromFile)
service_controller.init();
auto services_to_port_map = i_service_controller->getServiceToPortMap();
EXPECT_EQ(services_to_port_map.find("family1_id3")->second, family1_id3_port);
vector<PortNumber> ports = {l4_firewall_service_port, family1_id3_port};
EXPECT_EQ(services_to_port_map.find("mock access control")->second, ports);
}
TEST_F(ServiceControllerTest, noPolicyUpdate)
@ -1589,7 +1611,7 @@ TEST_F(ServiceControllerTest, testPortsRest)
empty_json << "{}";
auto res = get_services_ports->performRestCall(empty_json);
ASSERT_TRUE(res.ok());
EXPECT_THAT(res.unpack(), HasSubstr("family1_id2:8888"));
EXPECT_THAT(res.unpack(), HasSubstr("mock-access-control:8888;"));
}
TEST_F(ServiceControllerTest, testMultitenantConfFiles)

View File

@ -184,6 +184,8 @@ FogAuthenticator::registerAgent(
request << make_pair("cloudAccountId", ::get<0>(cloud_metadata.unpack()));
request << make_pair("cloudVpcId", ::get<1>(cloud_metadata.unpack()));
request << make_pair("cloudInstanceId", ::get<2>(cloud_metadata.unpack()));
request << make_pair("cloudInstanceLocalIp", ::get<3>(cloud_metadata.unpack()));
request << make_pair("cloudRegion", ::get<4>(cloud_metadata.unpack()));
} else {
dbgDebug(D_ORCHESTRATOR) << cloud_metadata.getErr();
}

View File

@ -32,6 +32,7 @@
using namespace std;
USE_DEBUG_FLAG(D_ORCHESTRATOR);
class UpdateCommunication::Impl
:
public ServerRest,

View File

@ -0,0 +1 @@
add_library(updates_process_reporter updates_process_event.cc updates_process_reporter.cc)

View File

@ -0,0 +1,124 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (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.
#include "updates_process_event.h"
#include <sstream>
#include <string>
#include "debug.h"
using namespace std;
USE_DEBUG_FLAG(D_UPDATES_PROCESS_REPORTER);
UpdatesProcessEvent::UpdatesProcessEvent(
UpdatesProcessResult _result,
UpdatesConfigType _type,
UpdatesFailureReason _reason,
const std::string &_detail,
const std::string &_description)
:
result(_result),
type(_type),
reason(_reason),
detail(_detail),
description(_description)
{
string report =
"Result: " + convertUpdateProcessResultToStr(result) +
", Reason: " + convertUpdatesFailureReasonToStr(reason) +
", Type: " + convertUpdatesConfigTypeToStr(type) +
", Detail: " + detail +
", Description: " + description;
dbgTrace(D_UPDATES_PROCESS_REPORTER) << "Updates process event: " << report;
}
OrchestrationStatusFieldType
UpdatesProcessEvent::getStatusFieldType() const
{
if (reason == UpdatesFailureReason::REGISTRATION) {
return OrchestrationStatusFieldType::REGISTRATION;
}
if (type == UpdatesConfigType::MANIFEST) {
return OrchestrationStatusFieldType::MANIFEST;
}
return OrchestrationStatusFieldType::LAST_UPDATE;
}
OrchestrationStatusResult
UpdatesProcessEvent::getOrchestrationStatusResult() const
{
return result == UpdatesProcessResult::SUCCESS ?
OrchestrationStatusResult::SUCCESS :
OrchestrationStatusResult::FAILED;
}
string
UpdatesProcessEvent::parseDescription() const
{
stringstream err;
if (description.empty() || result == UpdatesProcessResult::SUCCESS) return "";
switch (reason) {
case UpdatesFailureReason::CHECK_UPDATE: {
err << description;
break;
}
case UpdatesFailureReason::REGISTRATION: {
err << "Registration failed. Error: " << description;
break;
}
case UpdatesFailureReason::GET_UPDATE_REQUEST: {
err << "Failed to get update request. Error: " << description;
break;
}
case UpdatesFailureReason::DOWNLOAD_FILE : {
err << "Failed to download the file " << detail << ". Error: " << description;
break;
}
case UpdatesFailureReason::HANDLE_FILE : {
err << "Failed to handle the file " << detail << ". " << description;
break;
}
case UpdatesFailureReason::INSTALLATION_QUEUE : {
err << "Installation queue creation failed. Error: " << description;
break;
}
case UpdatesFailureReason::INSTALL_PACKAGE : {
err << "Failed to install the package " << detail << ". Error: " << description;
break;
}
case UpdatesFailureReason::CHECKSUM_UNMATCHED : {
err << "Checksums do not match for the file: " << detail << ". " << description;
break;
}
case UpdatesFailureReason::POLICY_CONFIGURATION : {
err << "Failed to configure policy version: " << detail << ". Error: " << description;
break;
}
case UpdatesFailureReason::POLICY_FOG_CONFIGURATION : {
err << "Failed to configure the fog address: " << detail << ". Error: " << description;
break;
}
case UpdatesFailureReason::ORCHESTRATION_SELF_UPDATE : {
err << description;
break;
}
case UpdatesFailureReason::NONE : {
err << description;
break;
}
}
return err.str();
}

View File

@ -0,0 +1,71 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (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.
#include "updates_process_reporter.h"
#include <sstream>
#include <string>
#include "debug.h"
#include "log_generator.h"
using namespace std;
USE_DEBUG_FLAG(D_UPDATES_PROCESS_REPORTER);
vector<UpdatesProcessReport> UpdatesProcessReporter::reports;
void
UpdatesProcessReporter::upon(const UpdatesProcessEvent &event)
{
if (event.getReason() == UpdatesFailureReason::CHECK_UPDATE) {
if (event.getResult() == UpdatesProcessResult::SUCCESS && reports.empty()) {
dbgTrace(D_UPDATES_PROCESS_REPORTER) << "Update proccess finished successfully";
return;
}
dbgTrace(D_UPDATES_PROCESS_REPORTER) << "Update proccess finished with errors";
reports.emplace_back(
UpdatesProcessReport(
event.getResult(),
event.getType(),
event.getReason(),
event.parseDescription()
)
);
sendReoprt();
return;
}
if (event.getResult() == UpdatesProcessResult::SUCCESS || event.getResult() == UpdatesProcessResult::UNSET) return;
reports.emplace_back(
UpdatesProcessReport(event.getResult(), event.getType(), event.getReason(), event.parseDescription())
);
}
void
UpdatesProcessReporter::sendReoprt()
{
stringstream all_reports;
all_reports << "Updates process reports:" << endl;
for (const auto &report : reports) {
all_reports << report.toString() << endl;
}
reports.clear();
dbgTrace(D_UPDATES_PROCESS_REPORTER) << "Sending updates process report: " << endl << all_reports.str();
LogGen(
"Updates process report",
ReportIS::Audience::INTERNAL,
ReportIS::Severity::HIGH,
ReportIS::Priority::HIGH,
ReportIS::Tags::ORCHESTRATOR
) << LogField("eventMessage", all_reports.str());
}

View File

@ -273,55 +273,58 @@ DeepParser::onKv(const char *k, size_t k_len, const char *v, size_t v_len, int f
// Detect and decode potential base64 chunks in the value before further processing
bool base64ParamFound = false;
dbgTrace(D_WAAP_DEEP_PARSER) << " ===Processing potential base64===";
std::string decoded_val, decoded_key;
Waap::Util::BinaryFileType base64BinaryFileType = Waap::Util::BinaryFileType::FILE_TYPE_NONE;
base64_variants base64_status = Waap::Util::b64Test(cur_val, decoded_key, decoded_val, base64BinaryFileType);
if (m_depth == 1 && flags == BUFFERED_RECEIVER_F_MIDDLE && m_key.depth() == 1 && m_key.first() != "#base64"){
dbgTrace(D_WAAP_DEEP_PARSER) << " === will not check base64 since prev data block was not b64-encoded ===";
} else {
dbgTrace(D_WAAP_DEEP_PARSER) << " ===Processing potential base64===";
std::string decoded_val, decoded_key;
base64_variants base64_status = Waap::Util::b64Test(cur_val, decoded_key, decoded_val, base64BinaryFileType);
dbgTrace(D_WAAP_DEEP_PARSER)
<< " status = "
<< base64_status
<< " key = "
<< decoded_key
<< " value = "
<< decoded_val;
dbgTrace(D_WAAP_DEEP_PARSER)
<< " status = "
<< base64_status
<< " key = "
<< decoded_key
<< " value = "
<< decoded_val;
switch (base64_status) {
case SINGLE_B64_CHUNK_CONVERT:
cur_val = decoded_val;
base64ParamFound = true;
break;
case KEY_VALUE_B64_PAIR:
// going deep with new pair in case value is not empty
if (decoded_val.size() > 0) {
switch (base64_status) {
case SINGLE_B64_CHUNK_CONVERT:
cur_val = decoded_val;
base64ParamFound = true;
rc = onKv(
decoded_key.c_str(),
decoded_key.size(),
cur_val.data(),
cur_val.size(),
flags,
parser_depth
break;
case KEY_VALUE_B64_PAIR:
// going deep with new pair in case value is not empty
if (decoded_val.size() > 0) {
cur_val = decoded_val;
base64ParamFound = true;
rc = onKv(
decoded_key.c_str(),
decoded_key.size(),
cur_val.data(),
cur_val.size(),
flags,
parser_depth
);
dbgTrace(D_WAAP_DEEP_PARSER) << " rc = " << rc;
if (rc != CONTINUE_PARSING) {
return rc;
dbgTrace(D_WAAP_DEEP_PARSER) << " rc = " << rc;
if (rc != CONTINUE_PARSING) {
return rc;
}
}
}
break;
case CONTINUE_AS_IS:
break;
default:
break;
}
break;
case CONTINUE_AS_IS:
break;
default:
break;
}
if (base64ParamFound) {
dbgTrace(D_WAAP_DEEP_PARSER) << "DeepParser::onKv(): pushing #base64 prefix to the key.";
m_key.push("#base64", 7, false);
if (base64ParamFound) {
dbgTrace(D_WAAP_DEEP_PARSER) << "DeepParser::onKv(): pushing #base64 prefix to the key.";
m_key.push("#base64", 7, false);
}
}
// cur_val is later passed through some filters (such as urldecode) before JSON, XML or HTML is detected/decoded
std::string orig_val = cur_val;
@ -472,19 +475,19 @@ DeepParser::onKv(const char *k, size_t k_len, const char *v, size_t v_len, int f
if (rc != CONTINUE_PARSING) {
return rc;
}
if (Waap::Util::detectJSONasParameter(cur_val, decoded_key, decoded_val)) {
std::string json_decoded_val, json_decoded_key;
if (Waap::Util::detectJSONasParameter(cur_val, json_decoded_key, json_decoded_val)) {
dbgTrace(D_WAAP_DEEP_PARSER)
<< " detectJSONasParameter was true: key = "
<< decoded_key
<< json_decoded_key
<< " value = "
<< decoded_val;
<< json_decoded_val;
rc = onKv(
decoded_key.c_str(),
decoded_key.size(),
decoded_val.data(),
decoded_val.size(),
json_decoded_key.c_str(),
json_decoded_key.size(),
json_decoded_val.data(),
json_decoded_val.size(),
flags,
parser_depth
);

View File

@ -22,6 +22,7 @@
#define BUFFERED_RECEIVER_F_LAST 0x02
#define BUFFERED_RECEIVER_F_BOTH (BUFFERED_RECEIVER_F_FIRST | BUFFERED_RECEIVER_F_LAST)
#define BUFFERED_RECEIVER_F_UNNAMED 0x04
#define BUFFERED_RECEIVER_F_MIDDLE 0x00
#if (DISTRO_centos6)
// pre c++11 compiler doesn' support the "final" keyword

View File

@ -727,7 +727,6 @@ void SerializeToLocalAndRemoteSyncBase::syncWorker()
"sync notification for '" + m_assetId + "'",
ReportIS::AudienceTeam::WAAP,
syncNotification,
false,
MessageCategory::GENERIC,
ReportIS::Tags::WAF,
ReportIS::Notification::SYNC_LEARNING

View File

@ -39,12 +39,19 @@ public:
m_op = to_lower_copy(m_op);
m_isCidr = false;
m_value = "";
m_isValid = true;
if (m_op == "basic") {
// If op == "BASIC" - read numeric value
ar(cereal::make_nvp("tag", m_tag));
m_tag = to_lower_copy(m_tag);
if (m_tag != "sourceip" && m_tag != "sourceidentifier" && m_tag != "url" && m_tag != "hostname" &&
m_tag != "keyword" && m_tag != "paramname" && m_tag != "paramvalue" && m_tag != "paramlocation" &&
m_tag != "responsebody" && m_tag != "headername" && m_tag != "headervalue" ) {
m_isValid = false;
dbgDebug(D_WAAP_OVERRIDE) << "Invalid override tag: " << m_tag;
}
// The name "value" here is misleading. The real meaning is "regex pattern string"
ar(cereal::make_nvp("value", m_value));
@ -73,12 +80,14 @@ public:
m_operand2 = std::make_shared<Match>();
ar(cereal::make_nvp("operand2", *m_operand2));
m_isOverrideResponse = m_operand1->m_isOverrideResponse || m_operand2->m_isOverrideResponse;
m_isValid = m_operand1->m_isValid && m_operand2->m_isValid;
}
else if (m_op == "not") {
// If op is "NOT" get one operand
m_operand1 = std::make_shared<Match>();
ar(cereal::make_nvp("operand1", *m_operand1));
m_isOverrideResponse = m_operand1->m_isOverrideResponse;
m_isValid = m_operand1->m_isValid;
}
}
}
@ -120,6 +129,10 @@ public:
return m_isOverrideResponse;
}
bool isValidMatch() const{
return m_isValid;
}
private:
std::string m_op;
std::shared_ptr<Match> m_operand1;
@ -130,6 +143,7 @@ private:
Waap::Util::CIDRData m_cidr;
bool m_isCidr;
bool m_isOverrideResponse;
bool m_isValid;
};
class Behavior
@ -189,6 +203,9 @@ private:
class Rule {
public:
Rule(): m_match(), m_isChangingRequestData(false), isValid(true){}
bool operator==(const Rule &other) const;
template <typename _A>
@ -202,6 +219,11 @@ public:
m_id.clear();
}
ar(cereal::make_nvp("parsedMatch", m_match));
if (!m_match.isValidMatch()) {
dbgDebug(D_WAAP_OVERRIDE) << "An override rule was not load";
isValid = false;
}
ar(cereal::make_nvp("parsedBehavior", m_behaviors));
m_isChangingRequestData = false;
@ -242,6 +264,7 @@ public:
dbgTrace(D_WAAP_OVERRIDE) << "Rule not matched";
}
bool isChangingRequestData() const {
return m_isChangingRequestData;
}
@ -253,11 +276,16 @@ public:
return m_id;
}
bool isValidRule() const {
return isValid;
}
private:
Match m_match;
bool m_isChangingRequestData;
std::vector<Behavior> m_behaviors;
std::string m_id;
bool isValid;
};
class Policy {
@ -270,6 +298,10 @@ public:
for (std::vector<Waap::Override::Rule>::const_iterator it = rules.begin(); it != rules.end(); ++it) {
const Waap::Override::Rule& rule = *it;
if (!rule.isValidRule()) {
dbgWarning(D_WAAP_OVERRIDE) << "rule is not valid";
continue;
}
if (rule.isChangingRequestData())
{
m_RequestOverrides.push_back(rule);

View File

@ -145,6 +145,6 @@ bool WaapOverrideFunctor::operator()(const std::string& tag, const boost::regex&
}
// Unknown tag: should not occur
dbgWarning(D_WAAP) << "Invalid override tag: " << tag;
dbgDebug(D_WAAP) << "Invalid override tag: " << tag;
return false;
}

View File

@ -1516,6 +1516,7 @@ Waf2Transaction::decideAfterHeaders()
return finalizeDecision(sitePolicy, shouldBlock);
}
// Note: the only user of the transactionResult structure filled by this method is waap_automation.
// TODO: Consider removing this parameter (and provide access to this information by other means)
int

View File

@ -567,12 +567,11 @@ Waap::Override::State Waf2Transaction::getOverrideState(IWaapConfig* sitePolicy)
extractEnvSourceIdentifier();
Waap::Override::State overrideStateResponse;
if (overridePolicy) { // later we will run response overrides
overrideStateResponse.applyOverride(*overridePolicy, WaapOverrideFunctor(*this), m_matchedOverrideIds, false);
m_overrideState.applyOverride(*overridePolicy, WaapOverrideFunctor(*this), m_matchedOverrideIds, false);
}
m_isHeaderOverrideScanRequired = false;
return overrideStateResponse;
return m_overrideState;
}
Waf2TransactionFlags &Waf2Transaction::getTransactionFlags()

View File

@ -175,7 +175,7 @@ copyFile(const string &src, const string &dest, bool overide_if_exists, mode_t p
struct stat stat_buf;
int source_fd = open(src.c_str(), O_RDONLY);
fstat(source_fd, &stat_buf);
int dest_fd = open(dest.c_str(), O_WRONLY | O_CREAT, permission);
int dest_fd = open(dest.c_str(), O_WRONLY | O_CREAT | O_TRUNC, permission);
int bytes_copied = 1;
while (bytes_copied > 0) {
static const int buf_size = 4096*1000;

View File

@ -37,8 +37,11 @@ TEST_F(AgentCoreUtilUT, filesTest)
EXPECT_FALSE(NGEN::Filesystem::exists("/i/am/not/a/real/path"));
const vector<string> lines{"i am a line in the text file", "i am iron man"};
const vector<string> lines_b{"i am a line 2 in the text file", "i am iron man 2", "hello again"};
CPTestTempfile test_file(lines);
CPTestTempfile test_file_b(lines_b);
ASSERT_TRUE(NGEN::Filesystem::exists(test_file.fname));
ASSERT_TRUE(NGEN::Filesystem::exists(test_file_b.fname));
string output_orig = test_file.readFile();
string new_path = test_file.fname + ".new";
@ -46,6 +49,7 @@ TEST_F(AgentCoreUtilUT, filesTest)
ASSERT_TRUE(NGEN::Filesystem::exists(new_path));
ASSERT_FALSE(NGEN::Filesystem::copyFile(test_file.fname, new_path, false));
ASSERT_TRUE(NGEN::Filesystem::copyFile(test_file.fname, new_path, true));
ASSERT_TRUE(NGEN::Filesystem::copyFile(test_file.fname, test_file_b.fname, true));
string output_new;
{
ifstream new_file_stream(new_path);
@ -55,11 +59,20 @@ TEST_F(AgentCoreUtilUT, filesTest)
output_new = buffer.str();
}
string output_test_b;
ifstream new_file_stream(test_file_b.fname);
ASSERT_TRUE(new_file_stream.good());
stringstream buffer;
buffer << new_file_stream.rdbuf();
output_test_b = buffer.str();
EXPECT_EQ(output_orig, output_new);
EXPECT_EQ(output_orig, output_test_b);
EXPECT_THAT(output_new, HasSubstr("i am a line in the text file"));
EXPECT_THAT(output_new, HasSubstr("i am iron man"));
EXPECT_TRUE(NGEN::Filesystem::deleteFile(test_file.fname));
EXPECT_TRUE(NGEN::Filesystem::deleteFile(new_path));
EXPECT_TRUE(NGEN::Filesystem::deleteFile(test_file_b.fname));
EXPECT_FALSE(NGEN::Filesystem::exists(test_file.fname));
EXPECT_FALSE(NGEN::Filesystem::exists(new_path));
}

View File

@ -348,14 +348,12 @@ ConfigComponent::Impl::init()
if (!Singleton::exists<I_MainLoop>()) return;
auto mainloop = Singleton::Consume<I_MainLoop>::by<ConfigComponent>();
if (executable_name != "cp-nano-orchestration") {
mainloop->addOneTimeRoutine(
I_MainLoop::RoutineType::System,
[this] () { periodicRegistrationRefresh(); },
"Configuration update registration",
false
);
}
mainloop->addOneTimeRoutine(
I_MainLoop::RoutineType::System,
[this] () { periodicRegistrationRefresh(); },
"Configuration update registration",
false
);
}
static bool

View File

@ -234,6 +234,55 @@ public:
static DebugConfiguration default_config;
class ChangeDebugConfiguration : public ServerRest
{
public:
void
doCall() override
{
string debug_config_file_name = Debug::getExecutableName();
if (debug_config_file_name == "") {
output = "Error. Cannot get debug config file path";
return;
}
string debug_config_file_path = getConfigurationWithDefault<string>(
getFilesystemPathConfig() + "/conf/" + debug_config_file_name + "-debug-conf.json",
"Debug I/S",
"Debug conf file path"
);
try {
ifstream input_stream(debug_config_file_path);
if (!input_stream) {
output = "Error. Cannot open the debug conf file: " + debug_config_file_path;
return;
}
cereal::JSONInputArchive ar(input_stream);
Debug::prepareConfig();
vector<DebugConfiguration> debug_config;
try {
ar(cereal::make_nvp("Debug", debug_config));
} catch (cereal::Exception &e) {
output = "Error. Failed loading debug conf file, error: " + string(e.what());
Debug::abortConfig();
return;
}
input_stream.close();
setConfiguration(debug_config[0], "Debug");
Debug::commitConfig();
output = "New debug configuration set succesfully";
} catch (ifstream::failure &f) {
output =
"Error. Cannot open the debug conf file " +
debug_config_file_path +
", error: " +
string(f.what());
}
}
private:
S2C_PARAM(string, output);
};
// LCOV_EXCL_START - function is covered in unit-test, but not detected bt gcov
Debug::Debug(
const string &file_name,
@ -446,6 +495,7 @@ Debug::preload()
{
registerExpectedConfiguration<DebugConfiguration>("Debug");
registerExpectedConfiguration<string>("Debug I/S", "Fog Debug URI");
registerExpectedConfiguration<string>("Debug I/S", "Debug conf file path");
registerExpectedConfiguration<bool>("Debug I/S", "Enable bulk of debugs");
registerExpectedConfiguration<uint>("Debug I/S", "Debug bulk size");
registerExpectedConfiguration<uint>("Debug I/S", "Debug bulk sending interval in msec");
@ -467,22 +517,18 @@ Debug::init()
mainloop = Singleton::Consume<I_MainLoop>::by<Debug>();
env = Singleton::Consume<I_Environment>::by<Debug>();
auto executable = env->get<string>("Executable Name");
if (executable.ok() && *executable != "") {
string default_debug_output_file_path = *executable;
auto file_path_end = default_debug_output_file_path.find_last_of("/");
if (file_path_end != string::npos) {
default_debug_file_stream_path = default_debug_output_file_path.substr(file_path_end + 1);
}
auto file_sufix_start = default_debug_file_stream_path.find_first_of(".");
if (file_sufix_start != string::npos) {
default_debug_file_stream_path = default_debug_file_stream_path.substr(0, file_sufix_start);
}
default_debug_file_stream_path = getExecutableName();
if (default_debug_file_stream_path != "") {
string log_files_prefix = getLogFilesPathConfig();
default_debug_file_stream_path = log_files_prefix + "/nano_agent/" + default_debug_file_stream_path + ".dbg";
}
if (Singleton::exists<I_RestApi>()) {
Singleton::Consume<I_RestApi>::by<Debug>()->addRestCall<ChangeDebugConfiguration>(
RestAction::SET,
"change-debug-config"
);
}
}
void
@ -706,6 +752,27 @@ Debug::findDebugFilePrefix(const string &file_name)
return "";
}
string
Debug::getExecutableName()
{
auto executable = env->get<string>("Executable Name");
if (!executable.ok() || *executable == "") {
return "";
}
string executable_name = *executable;
auto file_path_end = executable_name.find_last_of("/");
if (file_path_end != string::npos) {
executable_name = executable_name.substr(file_path_end + 1);
}
auto file_sufix_start = executable_name.find_first_of(".");
if (file_sufix_start != string::npos) {
executable_name = executable_name.substr(0, file_sufix_start);
}
return executable_name;
}
void
Debug::addActiveStream(const string &name)
{

View File

@ -21,6 +21,7 @@
#include "report/report.h"
#include "i_agent_details.h"
#include "i_environment.h"
#include "i_rest_api.h"
#include "i_mainloop.h"
#include "report/report_bulks.h"

View File

@ -0,0 +1,13 @@
{
"Debug": [
{
"Streams": [
{
"D_ALL": "Info",
"D_FW": "Debug",
"Output": "/var/log/nano_agent/cp-nano-orchestration.dbg"
}
]
}
]
}

View File

@ -14,6 +14,7 @@
#include "mock/mock_messaging.h"
#include "mock/mock_mainloop.h"
#include "mock/mock_environment.h"
#include "mock/mock_rest_api.h"
#include "mock/mock_instance_awareness.h"
using namespace std;
@ -551,7 +552,6 @@ public:
Debug::setNewDefaultStdout(&capture_debug);
}
~DebugConfigTest()
{
loadConfiguration("");
@ -583,10 +583,19 @@ public:
Singleton::Consume<Config::I_Config>::from(conf)->loadConfiguration(configuration);
}
bool
setDebugConfig(const unique_ptr<RestInit> &p)
{
set_debug_config = p->getRest();
return true;
}
ConfigComponent conf;
::Environment env;
stringstream capture_debug;
StrictMock<MockAgentDetails> mock_agent_details;
NiceMock<MockRestApi> mock_rest;
unique_ptr<ServerRest> set_debug_config;
};
TEST_F(DebugConfigTest, basic_configuration)
@ -786,6 +795,54 @@ TEST_F(DebugConfigTest, fail_configuration)
EXPECT_FALSE(loadConfiguration(debug_config));
}
TEST_F(DebugConfigTest, testSetConfig)
{
NiceMock<MockMainLoop> mock_mainloop;
StrictMock<MockTimeGet> mock_time;
Debug::setUnitTestFlag(D_FW, Debug::DebugLevel::WARNING);
EXPECT_TRUE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::ERROR));
EXPECT_FALSE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::INFO));
EXPECT_FALSE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::DEBUG));
EXPECT_FALSE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::TRACE));
EXPECT_CALL(mock_rest, mockRestCall(RestAction::SET, "change-debug-config", _))
.WillOnce(WithArg<2>(Invoke(this, &DebugConfigTest::setDebugConfig))
);
Maybe<I_MainLoop::RoutineID> error_id = genError("no id");
EXPECT_CALL(mock_mainloop, getCurrentRoutineId()).WillRepeatedly(Return(error_id));
EXPECT_CALL(mock_time, getWalltimeStr()).WillRepeatedly(Return(string("")));
EXPECT_CALL(mock_rest, mockRestCall(RestAction::ADD, "declare-boolean-variable", _)).WillOnce(Return(true));
env.preload();
Singleton::Consume<I_Environment>::from(env)->registerValue<string>("Executable Name", "debug-ut");
env.init();
Debug::init();
setConfiguration(
cptestFnameInSrcDir(string("debug-ut-debug-conf.json")),
string("Debug I/S"),
string("Debug conf file path")
);
stringstream ss("{}");
Maybe<string> maybe_res = set_debug_config->performRestCall(ss);
ASSERT_TRUE(maybe_res.ok());
EXPECT_EQ(maybe_res.unpack(), "{\n \"output\": \"New debug configuration set succesfully\"\n}");
EXPECT_TRUE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::ERROR));
EXPECT_TRUE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::INFO));
EXPECT_TRUE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::DEBUG));
EXPECT_FALSE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::TRACE));
Debug::setUnitTestFlag(D_FW, Debug::DebugLevel::WARNING); // Reset debug level so it won't effect other tests
EXPECT_TRUE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::ERROR));
EXPECT_FALSE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::INFO));
EXPECT_FALSE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::DEBUG));
EXPECT_FALSE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::TRACE));
Debug::fini();
}
ACTION(InvokeMainLoopCB)
{
arg1();

View File

@ -58,7 +58,6 @@ public:
string getCurrentTrace() const override;
string getCurrentSpan() const override;
string getCurrentHeaders() override;
map<string, string> getCurrentHeadersMap() override;
void startNewTrace(bool new_span, const string &_trace_id) override;
@ -239,34 +238,6 @@ Environment::Impl::getCurrentSpan() const
return "";
}
string
Environment::Impl::getCurrentHeaders()
{
string tracing_headers;
auto trace_id = getCurrentTrace();
if (!trace_id.empty()) {
tracing_headers += "X-Trace-Id: " + trace_id + "\r\n";
} else {
string correlation_id_string = "00000000-0000-0000-0000-000000000000";
try {
boost::uuids::random_generator uuid_random_gen;
correlation_id_string = boost::uuids::to_string(uuid_random_gen());
} catch (const boost::uuids::entropy_error &e) {
dbgTrace(D_ENVIRONMENT)
<< "Failed to generate random correlation id - entropy exception. Exception: "
<< e.what();
tracing_status = TracingStatus::DISABLED;
}
tracing_headers += "X-Trace-Id: " + correlation_id_string + "\r\n";
}
auto span_id = getCurrentSpan();
if (!span_id.empty()) {
tracing_headers += "X-Span-Id: " + span_id + "\r\n";
}
return tracing_headers;
}
map<string, string>
Environment::Impl::getCurrentHeadersMap()
{
@ -292,6 +263,21 @@ Environment::Impl::getCurrentHeadersMap()
if (!span_id.empty()) {
tracing_headers["X-Span-Id"] = span_id;
}
auto exec_name = get<string>("Executable Name");
if (exec_name.ok() && *exec_name != "") {
string executable_name = *exec_name;
auto file_path_end = executable_name.find_last_of("/");
if (file_path_end != string::npos) {
executable_name = executable_name.substr(file_path_end + 1);
}
auto file_sufix_start = executable_name.find_first_of(".");
if (file_sufix_start != string::npos) {
executable_name = executable_name.substr(0, file_sufix_start);
}
tracing_headers["X-Calling-Service"] = executable_name;
}
return tracing_headers;
}

View File

@ -345,12 +345,16 @@ public:
TEST_F(TracingCompRoutinesTest, 2SpansDifFlow)
{
I_MainLoop::Routine routine = [&] () {
string service_name = "test-service-name";
i_env->registerValue("Executable Name", service_name);
i_env->startNewTrace(true, "a687b388-1108-4083-9852-07c33b1074e9");
trace_id = i_env->getCurrentTrace();
span_id = i_env->getCurrentSpan();
string headers = i_env->getCurrentHeaders();
EXPECT_THAT(headers, HasSubstr("X-Trace-Id: " + trace_id));
EXPECT_THAT(headers, HasSubstr("X-Span-Id: " + span_id));
auto headers = i_env->getCurrentHeadersMap();
EXPECT_THAT(headers["X-Trace-Id"], trace_id);
EXPECT_THAT(headers["X-Span-Id"], span_id);
EXPECT_THAT(headers["X-Calling-Service"], service_name);
EXPECT_EQ(trace_id, "a687b388-1108-4083-9852-07c33b1074e9");
EXPECT_NE("", i_env->getCurrentSpan());

View File

@ -30,6 +30,7 @@ class I_Environment;
class I_InstanceAwareness;
class I_Encryptor;
class I_AgentDetails;
class I_RestApi;
class I_SignalHandler;
namespace Config { enum class Errors; }
@ -44,6 +45,7 @@ class Debug
Singleton::Consume<I_Environment>,
Singleton::Consume<I_Encryptor>,
Singleton::Consume<I_AgentDetails>,
Singleton::Consume<I_RestApi>,
Singleton::Consume<I_SignalHandler>
{
public:
@ -178,6 +180,7 @@ public:
static void setUnitTestFlag(DebugFlags flag, DebugLevel level);
static std::string findDebugFilePrefix(const std::string &file_name);
static std::string getExecutableName();
private:
template <typename T, typename... Args>

View File

@ -26,6 +26,7 @@
#include "i_time_get.h"
#include "i_encryptor.h"
#include "i_shell_cmd.h"
#include "i_rest_api.h"
#include "i_instance_awareness.h"
#include "config.h"
@ -41,6 +42,7 @@ class Messaging
Singleton::Consume<I_TimeGet>,
Singleton::Consume<I_ShellCmd>,
Singleton::Consume<I_MainLoop>,
Singleton::Consume<I_RestApi>,
Singleton::Consume<I_InstanceAwareness>
{
public:

View File

@ -79,7 +79,6 @@ public:
virtual std::string getCurrentTrace() const = 0;
virtual std::string getCurrentSpan() const = 0;
virtual std::string getCurrentHeaders() = 0;
virtual std::map<std::string, std::string> getCurrentHeadersMap() = 0;
virtual void startNewTrace(bool new_span = true, const std::string &_trace_id = std::string()) = 0;
virtual void startNewSpan(

View File

@ -46,11 +46,17 @@ public:
const std::vector<QueryRequest> &query_requests,
bool is_pretty,
bool is_bulk,
bool is_proxy,
const MessageMetadata &req_md
) const = 0;
virtual Maybe<Intelligence::Response>
getResponse(const QueryRequest &query_request, bool is_pretty, const MessageMetadata &req_md) const = 0;
getResponse(
const QueryRequest &query_request,
bool is_pretty,
bool is_proxy,
const MessageMetadata &req_md
) const = 0;
template<typename Data>
Maybe<std::vector<AssetReply<Data>>>
@ -58,6 +64,7 @@ public:
QueryRequest &query_request,
bool ignore_in_progress = false,
bool is_pretty = true,
bool is_proxy = false,
MessageMetadata req_md = MessageMetadata("", 0)
);
@ -66,6 +73,7 @@ public:
queryIntelligence(
std::vector<QueryRequest> &query_requests,
bool is_pretty = true,
bool is_proxy = false,
MessageMetadata req_md = MessageMetadata("", 0)
);

View File

@ -24,10 +24,11 @@ I_Intelligence_IS_V2::queryIntelligence(
QueryRequest &query_request,
bool ignore_in_progress,
bool is_pretty,
bool is_proxy,
MessageMetadata req_md
)
{
auto response = getResponse(query_request, is_pretty, req_md);
auto response = getResponse(query_request, is_pretty, is_proxy, req_md);
if (!response.ok()) return response.passErr();
auto serializable_response = response->getSerializableResponse<Data>();
@ -49,10 +50,11 @@ Maybe<std::vector<Maybe<std::vector<AssetReply<Data>>>>>
I_Intelligence_IS_V2::queryIntelligence(
std::vector<QueryRequest> &query_requests,
bool is_pretty,
bool is_proxy,
MessageMetadata req_md
)
{
auto res = getResponse(query_requests, is_pretty, true, req_md);
auto res = getResponse(query_requests, is_pretty, true, is_proxy, req_md);
if (!res.ok()) return res.passErr();
return res->getBulkData<Data>();

View File

@ -73,6 +73,7 @@ public:
SerializableQueryFilter(Condition condition_type, const std::string &key, const std::string &value);
SerializableQueryFilter(Condition condition_type, const std::string &key, const int64_t &value);
SerializableQueryFilter(Condition condition_type, const std::string &key, const std::vector<std::string> &value);
SerializableQueryFilter(const SerializableQueryCondition &condition);
void save(cereal::JSONOutputArchive &ar) const;

View File

@ -28,7 +28,6 @@ public:
MOCK_CONST_METHOD0(getCurrentTrace, std::string());
MOCK_CONST_METHOD0(getCurrentSpan, std::string());
MOCK_METHOD0(getCurrentHeaders, std::string());
MOCK_METHOD0(getCurrentHeadersMap, std::map<std::string, std::string>());
MOCK_METHOD2(startNewTrace, void(bool, const std::string &));
MOCK_METHOD3(startNewSpan, void(Span::ContextType, const std::string &, const std::string &));

View File

@ -26,21 +26,26 @@ public:
MOCK_CONST_METHOD1(sendInvalidation, bool(const Invalidation &invalidation));
MOCK_METHOD2(registerInvalidation, Maybe<uint>(const Invalidation &invalidation, const InvalidationCb &callback));
MOCK_METHOD1(unregisterInvalidation, void(uint id));
MOCK_CONST_METHOD4(
MOCK_CONST_METHOD5(
getResponse,
Maybe<Response>(
const std::vector<QueryRequest> &query_requests,
bool is_pretty,
bool is_bulk,
bool is_proxy,
const MessageMetadata &req_md
)
);
MOCK_CONST_METHOD3(
MOCK_CONST_METHOD4(
getResponse,
Maybe<Response>(const QueryRequest &query_request, bool is_pretty, const MessageMetadata &req_md)
Maybe<Response>(
const QueryRequest &query_request,
bool is_pretty,
bool is_proxy,
const MessageMetadata &req_md
)
);
MOCK_CONST_METHOD0(getIsOfflineOnly, bool(void));
MOCK_CONST_METHOD1(getOfflineInfoString, Maybe<std::string>(const SerializableQueryFilter &query));
};
#endif // __MOCK_INTELLIGENCE_H__

View File

@ -209,13 +209,13 @@ class ComponentListCore
ShellCmd,
GenericMetric,
Messaging,
MainloopComponent,
ConfigComponent,
InstanceAwareness,
IntelligenceComponentV2,
AgentDetails,
LoggingComp,
TimeProxyComponent,
MainloopComponent,
SignalHandler,
RestServer,
Encryptor,

View File

@ -142,6 +142,7 @@ DEFINE_FLAG(D_COMPONENT, D_ALL)
DEFINE_FLAG(D_LOCAL_POLICY, D_ORCHESTRATOR)
DEFINE_FLAG(D_NGINX_POLICY, D_ORCHESTRATOR)
DEFINE_FLAG(D_SERVICE_CONTROLLER, D_ORCHESTRATOR)
DEFINE_FLAG(D_UPDATES_PROCESS_REPORTER, D_ORCHESTRATOR)
DEFINE_FLAG(D_GRADUAL_DEPLOYMENT, D_COMPONENT)
DEFINE_FLAG(D_SDWAN, D_COMPONENT)

View File

@ -89,11 +89,4 @@ private:
std::map<std::string, std::string> extended_status = {};
};
class HealthCheckStatusEvent : public Event<HealthCheckStatusEvent, HealthCheckStatusReply>
{
public:
HealthCheckStatusEvent() {}
~HealthCheckStatusEvent() {}
};
#endif // __HEALTH_CHECK_STATUS_H__

View File

@ -69,6 +69,8 @@ enum class Tags {
NGINX_PROXY_MANAGER,
WEB_SERVER_APISIX,
DEPLOYMENT_DOCKER,
WEB_SERVER_SWAG,
WEB_SERVER_NGINX_UNIFIED,
COUNT
};

View File

@ -29,10 +29,11 @@ public:
const std::vector<QueryRequest> &queries,
bool is_pretty,
bool is_bulk,
bool _is_proxy,
const MessageMetadata &req_md
)
:
queries(queries), is_pretty(is_pretty), is_bulk(is_bulk), req_md(req_md)
queries(queries), is_pretty(is_pretty), is_bulk(is_bulk), is_proxy(_is_proxy), req_md(req_md)
{}
Maybe<void> checkAssetsLimit() const;
@ -51,6 +52,7 @@ private:
const std::vector<QueryRequest> &queries;
bool is_pretty = true;
bool is_bulk = false;
bool is_proxy = false;
Maybe<std::string> response_from_fog = genError("Uninitialized");
const MessageMetadata &req_md;
};

View File

@ -340,10 +340,11 @@ public:
const vector<QueryRequest> &query_requests,
bool is_pretty,
bool is_bulk,
bool is_proxy,
const MessageMetadata &req_md
) const override
{
IntelligenceRequest intelligence_req(query_requests, is_pretty, is_bulk, req_md);
IntelligenceRequest intelligence_req(query_requests, is_pretty, is_bulk, is_proxy, req_md);
if (!intelligence_req.checkAssetsLimit().ok()) return intelligence_req.checkAssetsLimit().passErr();
if (!intelligence_req.checkMinConfidence().ok()) return intelligence_req.checkMinConfidence().passErr();
if (intelligence_req.isPagingActivated()) {
@ -357,10 +358,15 @@ public:
}
Maybe<Intelligence::Response>
getResponse(const QueryRequest &query_request, bool is_pretty, const MessageMetadata &req_md) const override
getResponse(
const QueryRequest &query_request,
bool is_pretty,
bool is_proxy,
const MessageMetadata &req_md
) const override
{
vector<QueryRequest> queries = {query_request};
return getResponse(queries, is_pretty, false, req_md);
return getResponse(queries, is_pretty, false, is_proxy, req_md);
}
private:

View File

@ -131,7 +131,7 @@ TEST_F(IntelligenceComponentMockTest, getResponseErrorTest)
QueryRequest request(Condition::EQUALS, "category", "cloud", true);
Maybe<Intelligence::Response> res_error = genError("Test error");
EXPECT_CALL(intelligence_mock, getResponse(_, _, _)
EXPECT_CALL(intelligence_mock, getResponse(_, _, _, _)
).WillOnce(Return(res_error));
auto maybe_ans = intell->queryIntelligence<Profile>(request);
@ -185,7 +185,7 @@ TEST_F(IntelligenceComponentMockTest, getResponseTest)
Intelligence::Response response(response_str, 1, false);
EXPECT_CALL(intelligence_mock, getResponse(_, _, _)
EXPECT_CALL(intelligence_mock, getResponse(_, _, _, _)
).WillOnce(Return(response));
auto maybe_ans = intell->queryIntelligence<Profile>(request);
@ -346,7 +346,7 @@ TEST_F(IntelligenceComponentMockTest, bulkOnlineIntelligenceMockTest)
);
Intelligence::Response response(response_str, 4, true);
EXPECT_CALL(intelligence_mock, getResponse(_, _, _, _)
EXPECT_CALL(intelligence_mock, getResponse(_, _, _, _, _)
).WillOnce(Return(response));
auto maybe_ans = intell->queryIntelligence<Profile>(requests);

View File

@ -24,9 +24,33 @@ USE_DEBUG_FLAG(D_INTELLIGENCE);
TEST(IntelligenceQueryTestV2, genJsonPrettySingleRequest) {
QueryRequest request(Condition::EQUALS, "phase", "testing", true);
vector<QueryRequest> requests = {request};
Intelligence::IntelligenceRequest query(requests, true, false, MessageMetadata("", 0));
Intelligence::IntelligenceRequest query(requests, true, false, false, MessageMetadata("", 0));
std::string expected = "{\n"
" \"queryTypes\": {\n"
" \"proxyToCloud\": false\n"
" },\n"
" \"limit\": 20,\n"
" \"fullResponse\": true,\n"
" \"query\": {\n"
" \"operator\": \"equals\",\n"
" \"key\": \"mainAttributes.phase\",\n"
" \"value\": \"testing\"\n"
" }\n"
"}";
EXPECT_EQ(*query.genJson(), expected);
}
TEST(IntelligenceQueryTestV2, genJsonPrettySingleRequestProxied) {
QueryRequest request(Condition::EQUALS, "phase", "testing", true);
vector<QueryRequest> requests = {request};
Intelligence::IntelligenceRequest query(requests, true, false, true, MessageMetadata("", 0));
std::string expected = "{\n"
" \"queryTypes\": {\n"
" \"proxyToCloud\": true\n"
" },\n"
" \"limit\": 20,\n"
" \"fullResponse\": true,\n"
" \"query\": {\n"
@ -42,9 +66,12 @@ TEST(IntelligenceQueryTestV2, genJsonPrettySingleRequest) {
TEST(IntelligenceQueryTestV2, genJsonUnprettySingleRequest) {
QueryRequest request(Condition::EQUALS, "phase", "testing", true);
vector<QueryRequest> requests = {request};
Intelligence::IntelligenceRequest query(requests, false, false, MessageMetadata("", 0));
Intelligence::IntelligenceRequest query(requests, false, false, false, MessageMetadata("", 0));
std::string expected = "{"
"\"queryTypes\":{"
"\"proxyToCloud\":false"
"},"
"\"limit\":20,"
"\"fullResponse\":true,"
"\"query\":{"
@ -59,8 +86,11 @@ TEST(IntelligenceQueryTestV2, genJsonUnprettySingleRequest) {
TEST(IntelligenceQueryTestV2, genJsonUnprettySingleRequestSpaces) {
QueryRequest request(Condition::EQUALS, "ph ase", "te sti\" n g\\", true);
vector<QueryRequest> requests = {request};
Intelligence::IntelligenceRequest query(requests, false, false, MessageMetadata("", 0));
Intelligence::IntelligenceRequest query(requests, false, false, false, MessageMetadata("", 0));
std::string expected = "{"
"\"queryTypes\":{"
"\"proxyToCloud\":false"
"},"
"\"limit\":20,"
"\"fullResponse\":true,"
"\"query\":{"
@ -76,9 +106,53 @@ TEST(IntelligenceQueryTestV2, genJsonPrettyBulkRequests) {
QueryRequest request1(Condition::EQUALS, "phase", "testing", true);
QueryRequest request2(Condition::EQUALS, "height", "testing", 25);
std::vector<QueryRequest> requests = {request1, request2};
Intelligence::IntelligenceRequest query(requests, true, true, MessageMetadata("", 0));
Intelligence::IntelligenceRequest query(requests, true, true, false, MessageMetadata("", 0));
std::string expected = "{\n"
" \"queryTypes\": {\n"
" \"proxyToCloud\": false\n"
" },\n"
" \"queries\": [\n"
" {\n"
" \"query\": {\n"
" \"limit\": 20,\n"
" \"fullResponse\": true,\n"
" \"query\": {\n"
" \"operator\": \"equals\",\n"
" \"key\": \"mainAttributes.phase\",\n"
" \"value\": \"testing\"\n"
" }\n"
" },\n"
" \"index\": 0\n"
" },\n"
" {\n"
" \"query\": {\n"
" \"limit\": 20,\n"
" \"fullResponse\": true,\n"
" \"query\": {\n"
" \"operator\": \"equals\",\n"
" \"key\": \"mainAttributes.height\",\n"
" \"value\": \"testing\"\n"
" }\n"
" },\n"
" \"index\": 1\n"
" }\n"
" ]\n"
"}";
EXPECT_EQ(*query.genJson(), expected);
}
TEST(IntelligenceQueryTestV2, genJsonPrettyBulkRequestsProxied) {
QueryRequest request1(Condition::EQUALS, "phase", "testing", true);
QueryRequest request2(Condition::EQUALS, "height", "testing", 25);
std::vector<QueryRequest> requests = {request1, request2};
Intelligence::IntelligenceRequest query(requests, true, true, true, MessageMetadata("", 0));
std::string expected = "{\n"
" \"queryTypes\": {\n"
" \"proxyToCloud\": true\n"
" },\n"
" \"queries\": [\n"
" {\n"
" \"query\": {\n"
@ -114,9 +188,12 @@ TEST(IntelligenceQueryTestV2, genJsonUnprettyBulkRequest) {
QueryRequest request1(Condition::EQUALS, "phase", "testing", true);
QueryRequest request2(Condition::EQUALS, "height", "testing", 25);
std::vector<QueryRequest> requests = {request1, request2};
Intelligence::IntelligenceRequest query(requests, false, true, MessageMetadata("", 0));
Intelligence::IntelligenceRequest query(requests, false, true, false, MessageMetadata("", 0));
std::string expected = "{"
"\"queryTypes\":{"
"\"proxyToCloud\":false"
"},"
"\"queries\":[{"
"\"query\":{"
"\"limit\":20,"

View File

@ -705,3 +705,59 @@ TEST(QueryRequestTestV2, UninitializedObjectTypeTest)
EXPECT_THAT(debug_output.str(), HasSubstr(debug_str));
Debug::setNewDefaultStdout(&cout);
}
TEST(QueryRequestTestV2, Bug40968)
{
QueryRequest request(Intelligence_IS_V2::Condition::EQUALS, "field1", "123", false);
QueryRequest filter1(Intelligence_IS_V2::Condition::EQUALS, "field2", "123", false);
request = request || filter1;
QueryRequest filter2(Intelligence_IS_V2::Condition::NOT_EQUALS, "field3", "123", false);
request = request && filter2;
QueryRequest filter3(Intelligence_IS_V2::Condition::EQUALS, "field3", "234", false);
request = request && filter3;
stringstream out2;
{
cereal::JSONOutputArchive out_ar2(out2);
request.saveToJson(out_ar2);
}
string req =
"{\n"
" \"limit\": 20,\n"
" \"fullResponse\": false,\n"
" \"query\": {\n"
" \"operator\": \"and\",\n"
" \"operands\": [\n"
" {\n"
" \"operator\": \"or\",\n"
" \"operands\": [\n"
" {\n"
" \"operator\": \"equals\",\n"
" \"key\": \"mainAttributes.field1\",\n"
" \"value\": \"123\"\n"
" },\n"
" {\n"
" \"operator\": \"equals\",\n"
" \"key\": \"mainAttributes.field2\",\n"
" \"value\": \"123\"\n"
" }\n"
" ]\n"
" },\n"
" {\n"
" \"operator\": \"notEquals\",\n"
" \"key\": \"mainAttributes.field3\",\n"
" \"value\": \"123\"\n"
" },\n"
" {\n"
" \"operator\": \"equals\",\n"
" \"key\": \"mainAttributes.field3\",\n"
" \"value\": \"234\"\n"
" }\n"
" ]\n"
" }\n"
"}";
EXPECT_EQ(out2.str(), req);
}

View File

@ -89,6 +89,12 @@ IntelligenceRequest::genJson() const
JsonStream json_stream(&str_stream, is_pretty);
{
cereal::JSONOutputArchive out_ar(json_stream);
out_ar.setNextName("queryTypes");
out_ar.startNode();
out_ar(cereal::make_nvp("proxyToCloud", is_proxy));
out_ar.finishNode();
if (isBulk()) {
out_ar.setNextName("queries");
out_ar.startNode();

View File

@ -65,6 +65,11 @@ SerializableQueryFilter::SerializableQueryFilter(
condition_operands.emplace_back(condition_type, key, value);
}
SerializableQueryFilter::SerializableQueryFilter(const SerializableQueryCondition &condition)
{
condition_operands.push_back(condition);
}
SerializableQueryFilter::SerializableQueryFilter(
Condition condition_type,
@ -159,31 +164,38 @@ SerializableQueryFilter::calcOperator(const SerializableQueryFilter &other_query
query_filter_res.operator_type = oper;
if (isOperatorComp(oper) && other_query.isOperatorComp(oper)) {
size_t queries_size = queries_operands.size() + other_query.queries_operands.size();
size_t conditions_size = condition_operands.size() + other_query.condition_operands.size();
query_filter_res.queries_operands.reserve(queries_size);
query_filter_res.condition_operands.reserve(conditions_size);
for (const auto &subquery : queries_operands) {
query_filter_res.queries_operands.push_back(subquery);
}
for (const auto &condition : condition_operands) {
query_filter_res.condition_operands.push_back(condition);
}
for (const auto &subquery : other_query.queries_operands) {
query_filter_res.queries_operands.push_back(subquery);
}
for (const auto &condition : other_query.condition_operands) {
query_filter_res.condition_operands.push_back(condition);
}
} else {
if (!isOperatorComp(oper) || !other_query.isOperatorComp(oper)) {
query_filter_res.queries_operands.reserve(2);
query_filter_res.queries_operands.push_back(*this);
query_filter_res.queries_operands.push_back(other_query);
return query_filter_res;
}
if (!condition_operands.empty() && !other_query.condition_operands.empty()) {
query_filter_res.condition_operands.reserve(queries_operands.size() + other_query.queries_operands.size());
for (const auto &condition : condition_operands) {
query_filter_res.condition_operands.push_back(condition);
}
for (const auto &condition : other_query.condition_operands) {
query_filter_res.condition_operands.push_back(condition);
}
return query_filter_res;
}
size_t queries_size = queries_operands.size() + other_query.queries_operands.size();
size_t conditions_size = condition_operands.size() + other_query.condition_operands.size();
query_filter_res.queries_operands.reserve(queries_size + conditions_size);
for (const auto &subquery : queries_operands) {
query_filter_res.queries_operands.push_back(subquery);
}
for (const auto &condition : condition_operands) {
query_filter_res.queries_operands.emplace_back(condition);
}
for (const auto &subquery : other_query.queries_operands) {
query_filter_res.queries_operands.push_back(subquery);
}
for (const auto &condition : other_query.condition_operands) {
query_filter_res.queries_operands.emplace_back(condition);
}
return query_filter_res;

View File

@ -18,6 +18,7 @@
#include "agent_core_utilities.h"
#include "connection_comp.h"
#include "rest.h"
#include "debug.h"
#include "messaging_buffer.h"
@ -25,6 +26,40 @@ using namespace std;
USE_DEBUG_FLAG(D_MESSAGING);
class FogConnectionChecker : public ServerRest
{
public:
void
doCall() override
{
dbgTrace(D_MESSAGING) << "Checking connection to the FOG";
auto response = Singleton::Consume<I_Messaging>::from<Messaging>()->sendSyncMessage(
HTTPMethod::GET,
"/access-manager/health/live",
string("")
);
if (!response.ok()) {
dbgTrace(D_MESSAGING) << "Failed to check connection to the FOG";
connected_to_fog = false;
error = response.getErr().toString();
return;
}
if (response.unpack().getHTTPStatusCode() == HTTPStatusCode::HTTP_OK) {
dbgTrace(D_MESSAGING) << "Connected to the FOG";
connected_to_fog = true;
error = "";
} else {
dbgTrace(D_MESSAGING) << "No connection to the FOG";
connected_to_fog = false;
error = response.unpack().toString();
}
}
private:
S2C_PARAM(bool, connected_to_fog);
S2C_PARAM(string, error);
};
void
MessagingComp::init()
{
@ -42,6 +77,13 @@ MessagingComp::init()
"message",
"Buffer Failed Requests"
);
if (Singleton::exists<I_RestApi>()) {
Singleton::Consume<I_RestApi>::by<Messaging>()->addRestCall<FogConnectionChecker>(
RestAction::SHOW,
"check-fog-connection"
);
}
}
static bool

View File

@ -15,6 +15,8 @@
#include "mocks/mock_messaging_connection.h"
#include "rest.h"
#include "rest_server.h"
#include "mock/mock_messaging.h"
#include "mock/mock_rest_api.h"
#include "dummy_socket.h"
using namespace std;
@ -26,12 +28,6 @@ operator<<(ostream &os, const Maybe<BufferedMessage> &)
return os;
}
static std::ostream &
operator<<(std::ostream &os, const HTTPResponse &)
{
return os;
}
static std::ostream &
operator<<(std::ostream &os, const HTTPStatusCode &)
{
@ -51,6 +47,9 @@ public:
{
Debug::setUnitTestFlag(D_MESSAGING, Debug::DebugLevel::TRACE);
EXPECT_CALL(mock_time_get, getMonotonicTime()).WillRepeatedly(Return(chrono::microseconds(0)));
EXPECT_CALL(mock_rest, mockRestCall(RestAction::SHOW, "check-fog-connection", _))
.WillOnce(WithArg<2>(Invoke(this, &TestMessagingComp::showFogConnection))
);
ON_CALL(mock_agent_details, getFogDomain()).WillByDefault(Return(Maybe<string>(fog_addr)));
ON_CALL(mock_agent_details, getFogPort()).WillByDefault(Return(Maybe<uint16_t>(fog_port)));
@ -73,6 +72,13 @@ public:
EXPECT_CALL(mock_proxy_conf, getProxyAuthentication(_)).WillRepeatedly(Return(string("cred")));
}
bool
showFogConnection(const unique_ptr<RestInit> &p)
{
show_fog_connection = p->getRest();
return true;
}
const string fog_addr = "127.0.0.1";
int fog_port = 8080;
CPTestTempfile agent_details_file;
@ -85,16 +91,37 @@ public:
NiceMock<MockTimeGet> mock_time_get;
NiceMock<MockAgentDetails> mock_agent_details;
NiceMock<MockProxyConfiguration> mock_proxy_conf;
NiceMock<MockRestApi> mock_rest;
NiceMock<MockMessaging> mock_message;
unique_ptr<ServerRest> show_fog_connection;
DummySocket dummy_socket;
};
TEST_F(TestMessagingComp, testInitComp)
TEST_F(TestMessagingComp, testCheckFogConnectivity)
{
EXPECT_CALL(
mock_mainloop, addRecurringRoutine(I_MainLoop::RoutineType::Timer, _, _, "Delete expired cache entries", _)
)
.WillOnce(Return(0));
messaging_comp.init();
setAgentDetails();
HTTPResponse res(
HTTPStatusCode::HTTP_OK,
string(
"{"
" \"up\": true,"
" \"timestamp\":\"\""
"}"
)
);
EXPECT_CALL(mock_message, sendSyncMessage(HTTPMethod::GET, "/access-manager/health/live", "", _, _))
.WillOnce(Return(res));
stringstream ss("{}");
Maybe<string> maybe_res = show_fog_connection->performRestCall(ss);
EXPECT_TRUE(maybe_res.ok());
EXPECT_EQ(maybe_res.unpack(),
"{\n"
" \"connected_to_fog\": true,\n"
" \"error\": \"\"\n"
"}"
);
}
TEST_F(TestMessagingComp, testSendSyncMessage)

View File

@ -111,7 +111,9 @@ TagAndEnumManagement::convertStringToTag(const string &tag)
{"Playground", ReportIS::Tags::PLAYGROUND},
{"Nginx Proxy Manager", ReportIS::Tags::NGINX_PROXY_MANAGER},
{"APISIX Server", ReportIS::Tags::WEB_SERVER_APISIX},
{"Docker Deployment", ReportIS::Tags::DEPLOYMENT_DOCKER}
{"Docker Deployment", ReportIS::Tags::DEPLOYMENT_DOCKER},
{"SWAG Server", ReportIS::Tags::WEB_SERVER_SWAG},
{"NGINX Unified Server", ReportIS::Tags::WEB_SERVER_NGINX_UNIFIED}
};
auto report_is_tag = strings_to_tags.find(tag);
@ -320,7 +322,9 @@ EnumArray<Tags, string> TagAndEnumManagement::tags_translation_arr {
"apiDiscoveryCloudMessaging",
"Nginx Proxy Manager",
"APISIX Server",
"Docker Deployment"
"Docker Deployment",
"SWAG Server",
"NGINX Unified Server"
};
EnumArray<AudienceTeam, string> TagAndEnumManagement::audience_team_translation {

View File

@ -2,7 +2,7 @@ set(VERSION_VARS_H_FILE ${CMAKE_CURRENT_BINARY_DIR}/version_vars.h)
set(BUILD_SCRIPT build_version_vars_h.py)
add_custom_command(
OUTPUT ${VERSION_VARS_H_FILE}
COMMAND CI_PIPELINE_ID=00000001 CI_BUILD_REF_NAME=open-source python3 ${BUILD_SCRIPT} "userspace" > ${VERSION_VARS_H_FILE}
COMMAND CI_PIPELINE_ID=00000001 CI_COMMIT_REF_NAME=open-source python3 ${BUILD_SCRIPT} "userspace" > ${VERSION_VARS_H_FILE}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${BUILD_SCRIPT}
)

View File

@ -15,7 +15,7 @@ timestamp = "%s%s" % (now.replace(microsecond=0).isoformat(), time.strftime("%z"
version_prefix = ""
full_version = "private"
branch = os.getenv("CI_BUILD_REF_NAME")
branch = os.getenv("CI_COMMIT_REF_NAME")
if branch is None:
branch = "private"

View File

@ -18,6 +18,7 @@ target_link_libraries(
orchestration
health_check
health_check_manager
updates_process_reporter
service_controller
manifest_controller
package_handler

View File

@ -52,7 +52,7 @@ log-triggers:
url-path: false
url-query: false
log-destination:
cloud: true
cloud: false
stdout:
format: json

View File

@ -13,7 +13,6 @@ DEFAULT_PORT_INDEX=2
DISPLAY_NAME_INDEX=3
SERVICE_PORTS_LIST_INDEX=4
PACKAGE_LIST_LINE_OFFSET=5
cp_nano_conf_location="conf"
@ -150,17 +149,21 @@ fi
all_services=""
lines_to_skip=$((PACKAGE_LIST_LINE_OFFSET))
{
while [ $lines_to_skip -ne 0 ]; do
read -r line
lines_to_skip=$((lines_to_skip - 1))
done
while read -r line; do
service_name="$(echo "$line" | cut -d "=" -f1 | tr "_" "-")"
all_services="${all_services} $service_name"
done
} <"${FILESYSTEM_PATH}/${CP_SCRIPTS_PATH}/${CP_NANO_PACKAGE_LIST_NAME}"
while IFS= read -r line; do
# Skip empty lines and lines that start with #
if [ -z "$(echo "${line}" | tr -d '[:space:]')" ]; then
continue
fi
if [ "${line#"#"}" != "$line" ]; then
continue
fi
service_name=$(echo "$line" | cut -d "=" -f1 | tr "_" "-")
# Check if the service name already exists in the list
if ! echo "$all_services" | grep -q "\<$service_name\>"; then
all_services="$all_services $service_name"
fi
done <"${FILESYSTEM_PATH}/${CP_SCRIPTS_PATH}/${CP_NANO_PACKAGE_LIST_NAME}"
is_valid_var_name() # Initials - ivvn
{
@ -392,7 +395,7 @@ extract_default_api_port() # Initials - edap
is_requested_service() # Initials - irs
{
irs_requested_service=$(echo "$1" | sed 's/-//g' | tr '[:upper:]' '[:lower:]')
irs_possible_service=$(echo "$2" | sed 's/-//g' | tr '[:upper:]' '[:lower:]')
irs_possible_service=$(echo "$2" | sed 's/^cp-nano-//' | sed 's/-//g' | tr '[:upper:]' '[:lower:]')
if [ "$irs_requested_service" = "$irs_possible_service" ]; then
echo true
return
@ -409,10 +412,10 @@ extract_api_port() # Initials - eap
return
fi
for pair in $(get_registered_services_ports | tr "," " "); do
for pair in $(get_registered_services_ports | tr ";" " "); do
eap_service="$(echo "$pair" | cut -d ':' -f1)"
if [ "$(is_requested_service "$eap_service_name" "$eap_service")" = true ]; then
echo "$pair" | cut -d ':' -f2
echo "$pair" | cut -d ':' -f2 | tr "," " "
return
fi
done
@ -638,7 +641,9 @@ run_update_gradual_policy() # Initials - rugp
rugp_service_api_port=$(extract_api_port "$rugp_service_name")
# Load gradual policy configuration
rugp_errors=$(curl_func "${rugp_service_api_port}" "set-gradual-deployment-policy" "${rugp_data}")
for port in $rugp_service_api_port; do
rugp_errors=$(curl_func "$port" "set-gradual-deployment-policy" "${rugp_data}")
done
sleep 1
if [ -n "$(echo "$rugp_errors" | sed "s/$(printf '\r')//g")" ]; then
echo "Failed to set gradual policy. Error: $rugp_errors"
@ -674,11 +679,9 @@ run_set_traffic_recording_policy() # Initials - rstrp
# Send signal to http_manager to update the traffic recording policy
rstrp_data='{"traffic_recording_flags":["'$1'"]}'
if [ "${remove_curl_ld_path}" = "true" ]; then
LD_LIBRARY_PATH="" ${curl_cmd} --noproxy "*" --header "Content-Type: application/json" --request POST --data "$rstrp_data" http://127.0.0.1:"$(extract_api_port 'http-manager')"/set-traffic-recording-policy
else
${curl_cmd} --noproxy "*" --header "Content-Type: application/json" --request POST --data "$rstrp_data" http://127.0.0.1:"$(extract_api_port 'http-manager')"/set-traffic-recording-policy
fi
for port in $(extract_api_port 'http-manager'); do
curl_func "$port" "set-traffic-recording-policy" "${rugp_data}"
done
sleep 1
}
@ -809,16 +812,20 @@ run_print_metrics() # Initials - rpm
if [ -z "$rpm_service_name" ]; then
print_metrics "Orchestration"
rpm_list=$(get_registered_services_ports | tr "," " ")
rpm_list=$(get_registered_services_ports | tr ";" " ")
for pair in ${rpm_list}; do
rpm_service=$(echo "$pair" | cut -d ':' -f1)
print_metrics "$rpm_service" "$(echo "$pair" | cut -d ':' -f2)"
rpm_port=$(echo "$pair" | cut -d ':' -f2)
for port in $(echo $rpm_port | tr "," " "); do
print_metrics "$rpm_service" "$port"
done
done
elif [ "$rpm_service_name" = "orchestration" ]; then
print_metrics "Orchestration"
else
rpm_port=$(extract_api_port "$rpm_service_name")
print_metrics "$rpm_service_name" "$rpm_port"
for port in $(extract_api_port "$rpm_service_name"); do
print_metrics "$rpm_service_name" "$port"
done
fi
}
@ -886,7 +893,7 @@ print_single_service_status() # Initials - psss
psss_is_userspace_process_running=$(is_userspace_running "$psss_service_name")
psss_maybe_version=$(LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$USR_LIB_PATH/cpnano"$LD_LIBRARY_PATH_ADD" $psss_service_full_path --version 2>&1)
if echo "$psss_maybe_version" | grep -q "error"; then
if echo "$psss_maybe_version" | grep -iq "error"; then
echo "Version: Temporarily unavailable"
format_colored_status_line "Status: Not Available"
echo ""
@ -1008,7 +1015,8 @@ run_status() # Initials - rs
fi
fi
if [ -n "$(cat ${FILESYSTEM_PATH}/conf/agent_details.json | grep "hybrid_mode")" ]; then
hybrid_mode=$(cat ${FILESYSTEM_PATH}/conf/agent_details.json | grep "hybrid_mode")
if [ -n "$hybrid_mode" ]; then
add_policy_file=true
rs_mgmt_mode_text="Local management"
else
@ -1019,8 +1027,16 @@ run_status() # Initials - rs
add_policy_file=true
rs_mgmt_mode_text="Cloud management (Visibility mode)"
fi
rs_profile_id=$(cat ${FILESYSTEM_PATH}/$cp_nano_conf_location/agent_details.json | grep "Profile ID" | cut -d '"' -f4)
fi
rs_agent_id=$(cat ${FILESYSTEM_PATH}/$cp_nano_conf_location/agent_details.json | grep "Agent ID" | cut -d '"' -f4)
echo "Management mode: ${rs_mgmt_mode_text}"
echo "Agent ID: ${rs_agent_id}"
if [ -z "$hybrid_mode" ]; then
echo "Profile ID: ${rs_profile_id}"
fi
if [ "${add_policy_file}" = "true" ]; then
echo "Policy files: "
@ -1189,6 +1205,7 @@ run_cpnano_debug() # Initials - rcd
{
CP_ENV_FILESYSTEM=${FILESYSTEM_PATH} CP_ENV_LOG_FILE=${LOG_FILE_PATH} ${FILESYSTEM_PATH}/${CP_SCRIPTS_PATH}/${CP_NANO_DEBUG_NAME} "${@}"
rcd_script_exit_code=$?
rcd_set_config_res=
# exit code of -1 from the script becomes 255 here
if [ $rcd_script_exit_code -eq 0 ]; then
exit 0
@ -1212,7 +1229,20 @@ run_cpnano_debug() # Initials - rcd
if [ "$rcd_load_all_settings" = "true" ]; then
for service in $all_services; do
if [ "$(is_userspace_running "${service}")" = "true" ]; then
run_load_settings "$service"
if [ "$service" = "orchestration" ]; then
rcd_set_config_res=$(curl_to_orchestration "set-change-debug-config")
else
for port in $(extract_api_port "$service"); do
rcd_set_config_res=$(curl_func $port "set-change-debug-config")
done
fi
rcd_service_formatted=$(format_nano_service_name "$service")
if echo "$rcd_set_config_res" | grep -q "Error"; then
echo "Failed to load debug configuration for $rcd_service_formatted service."
echo "$rcd_set_config_res"
else
echo "$rcd_service_formatted debug configuration updated successfully"
fi
fi
done
@ -1223,7 +1253,20 @@ run_cpnano_debug() # Initials - rcd
if [ -z "$1" ]; then
return
elif [ -n "$(get_nano_service_location_and_port "$1")" ]; then
run_load_settings "$1"
if [ "$1" = "orchestration" ]; then
rcd_set_config_res=$(curl_to_orchestration "set-change-debug-config")
else
for port in $(extract_api_port "$1"); do
rcd_set_config_res=$(curl_func $port "set-change-debug-config")
done
fi
rcd_service_formatted=$(format_nano_service_name "$1")
if echo "$rcd_set_config_res" | grep -q "Error"; then
echo "Failed to load debug configuration for $rcd_service_formatted service."
echo "$rcd_set_config_res"
else
echo "$rcd_service_formatted debug configuration updated successfully"
fi
fi
shift
done

View File

@ -418,9 +418,9 @@ cp_print()
printf "%b\n" "$1"
fi
if [ "$is_smb" != "1" ]; then
printf "%b\n" "$1" >> ${LOG_FILE_PATH}/${LOG_PATH}/${INSTALLATION_LOG_FILE}
printf "[%s] %b\n" "$(date +%Y-%m-%dT%H:%M:%S)" "$1" >> ${LOG_FILE_PATH}/${LOG_PATH}/${INSTALLATION_LOG_FILE}
else
printf "%b\n" "$1" >> ${SMB_LOG_FILE_PATH}/${LOG_PATH}/${INSTALLATION_LOG_FILE}
printf "[%s] %b\n" "$(date +%Y-%m-%dT%H:%M:%S)" "$1" >> ${SMB_LOG_FILE_PATH}/${LOG_PATH}/${INSTALLATION_LOG_FILE}
fi
}
@ -897,7 +897,7 @@ uninstall_messaging_proxy_if_needed()
get_status_content()
{
gsc_temp_old_status=$(sed -e 's/{\|}\|,\|"//g' -e '/^\s*$/d' -e 's/^ //' ${FILESYSTEM_PATH}/conf/orchestration_status.json)
gsc_temp_old_status=$(sed -e 's/{\|}\|,\|"//g' -e '/^\s*$/d' -e 's/^ //' ${FILESYSTEM_PATH}/conf/orchestration_status.json 2>1)
echo ${gsc_temp_old_status}
}
@ -956,9 +956,16 @@ install_orchestration()
add_uninstall_script
cp_exec "cp -f certificate/ngen.body.crt ${FILESYSTEM_PATH}/${CERTS_PATH}/fog.pem"
if [ -n ${OTP_TOKEN} ]; then
if [ -n "${OTP_TOKEN}" ]; then
cp_print "Saving authentication token to file"
printf '{\n "registration type": "token",\n "registration data": "%b"\n}' "$OTP_TOKEN" | ${FILESYSTEM_PATH}/${BIN_PATH}/${CP_NANO_BASE64} -e > ${FILESYSTEM_PATH}/${CONF_PATH}/registration-data.json
rm ${FILESYSTEM_PATH}/${CONF_PATH}/agent_details.json
rm ${FILESYSTEM_PATH}/${CONF_PATH}/orchestration_status.json
echo '{}'>${FILESYSTEM_PATH}/${CONF_PATH}/policy.json
if [ -f ${FILESYSTEM_PATH}/data/data5.a ]; then
rm ${FILESYSTEM_PATH}/data/data5.a
fi
fi
[ -f "${FILESYSTEM_PATH}/${SERVICE_PATH}/${ORCHESTRATION_FILE_NAME}.cfg" ] && . "${FILESYSTEM_PATH}/${SERVICE_PATH}/${ORCHESTRATION_FILE_NAME}.cfg"