Compare commits

..

25 Commits

Author SHA1 Message Date
Ned Wright
eddd250409 sync code 2024-09-15 02:49:26 +00:00
Ned Wright
f4bad4c4d9 Remove non-active files 2024-09-02 14:16:01 +03:00
WrightNed
6e916599d9 Merge pull request #179 from openappsec/Aug_20_2024-Dev
Aug 20th update
2024-08-27 12:33:46 +03:00
orianelou
24d53aed53 Update docker-compose.yaml 2024-08-27 10:50:25 +03:00
WrightNed
93fb3da2f8 Merge pull request #177 from wiaam96/patch-1
Update entry.sh
2024-08-22 15:17:49 +03:00
wiaam96
e7378c9a5f Update entry.sh 2024-08-22 15:15:24 +03:00
Ned Wright
110f0c8bd2 Aug 20th update 2024-08-21 08:42:14 +00:00
WrightNed
ca31aac08a Merge pull request #174 from openappsec/orianelou-patch-6
Update docker-compose.yaml
2024-08-20 15:17:02 +03:00
orianelou
161b6dd180 Update docker-compose.yaml 2024-08-20 14:50:01 +03:00
WrightNed
84327e0b19 Merge pull request #170 from openappsec/orianelou-patch-4
Create docker-compose.yaml
2024-08-05 13:12:40 +03:00
orianelou
b9723ba6ce Create docker-compose.yaml
added compose for docker SWAG
2024-08-05 12:06:37 +03:00
WrightNed
00e183b8c6 Merge pull request #169 from openappsec/Jul_31_2024-Dev
Jul 31st update
2024-08-01 18:10:44 +03:00
WrightNed
e859c167ed Merge pull request #167 from openappsec/orianelou-crds
Orianelou crds
2024-08-01 18:10:11 +03:00
Ned Wright
384b59cc87 Jul 31st update 2024-07-31 17:15:35 +00:00
orianelou
805e958cb9 Create open-appsec-crd-latest.yaml 2024-07-25 12:06:59 +03:00
orianelou
5bcd7cfcf1 Create open-appsec-crd-v1beta2.yaml 2024-07-25 12:05:57 +03:00
orianelou
ae6f2faeec Create open-appsec-crd-v1beta1.yaml 2024-07-25 12:04:22 +03:00
WrightNed
705a5e6061 Merge pull request #166 from openappsec/Jul_23_2024-Dev
Jul 23rd update
2024-07-24 16:01:45 +03:00
WrightNed
c33b74a970 Merge pull request #164 from chkp-omris/main
update intelligence
2024-07-24 15:54:58 +03:00
chkp-omris
2da9fbc385 update intelligence 2024-07-23 13:15:33 +00:00
Ned Wright
f58e9a6128 Jul 23rd update 2024-07-23 11:08:24 +00:00
WrightNed
57ea5c72c5 Merge pull request #156 from openappsec/Jul_04_2024-Dev
Jul 4th update
2024-07-07 08:47:38 +03:00
Ned Wright
962bd31d46 Jul 4th update 2024-07-04 14:10:34 +00:00
WrightNed
01770475ec Merge pull request #153 from openappsec/Jun_26_2024-Dev
June 27th update
2024-07-01 11:42:11 +03:00
Ned Wright
78b114a274 June 27th update 2024-06-27 12:05:38 +00:00
177 changed files with 107433 additions and 104159 deletions

View File

@@ -155,6 +155,24 @@ getWaitingForVerdictThreadTimeout()
return conf_data.getNumericalValue("waiting_for_verdict_thread_timeout_msec");
}
unsigned int
getMinRetriesForVerdict()
{
return conf_data.getNumericalValue("min_retries_for_verdict");
}
unsigned int
getMaxRetriesForVerdict()
{
return conf_data.getNumericalValue("max_retries_for_verdict");
}
unsigned int
getReqBodySizeTrigger()
{
return conf_data.getNumericalValue("body_size_trigger");
}
int
isIPAddress(c_str ip_str)
{

View File

@@ -63,31 +63,37 @@ TEST_F(HttpAttachmentUtilTest, GetValidAttachmentConfiguration)
"\"waiting_for_verdict_thread_timeout_msec\": 75,\n"
"\"req_header_thread_timeout_msec\": 10,\n"
"\"ip_ranges\": " + createIPRangesString(ip_ranges) + ",\n"
"\"static_resources_path\": \"" + static_resources_path + "\""
"\"static_resources_path\": \"" + static_resources_path + "\",\n"
"\"min_retries_for_verdict\": 1,\n"
"\"max_retries_for_verdict\": 3,\n"
"\"body_size_trigger\": 777\n"
"}\n";
ofstream valid_configuration_file(attachment_configuration_file_name);
valid_configuration_file << valid_configuration;
valid_configuration_file.close();
EXPECT_EQ(initAttachmentConfig(attachment_configuration_file_name.c_str()), 1);
EXPECT_EQ(getDbgLevel(), 2);
EXPECT_EQ(getDbgLevel(), 2u);
EXPECT_EQ(getStaticResourcesPath(), static_resources_path);
EXPECT_EQ(isFailOpenMode(), 0);
EXPECT_EQ(getFailOpenTimeout(), 1234);
EXPECT_EQ(getFailOpenTimeout(), 1234u);
EXPECT_EQ(isFailOpenHoldMode(), 1);
EXPECT_EQ(getFailOpenHoldTimeout(), 4321);
EXPECT_EQ(getFailOpenHoldTimeout(), 4321u);
EXPECT_EQ(isFailOpenOnSessionLimit(), 1);
EXPECT_EQ(getMaxSessionsPerMinute(), 0);
EXPECT_EQ(getNumOfNginxIpcElements(), 200);
EXPECT_EQ(getKeepAliveIntervalMsec(), 10000);
EXPECT_EQ(getResProccessingTimeout(), 420);
EXPECT_EQ(getReqProccessingTimeout(), 42);
EXPECT_EQ(getRegistrationThreadTimeout(), 101);
EXPECT_EQ(getReqHeaderThreadTimeout(), 10);
EXPECT_EQ(getReqBodyThreadTimeout(), 155);
EXPECT_EQ(getResHeaderThreadTimeout(), 1);
EXPECT_EQ(getResBodyThreadTimeout(), 0);
EXPECT_EQ(getWaitingForVerdictThreadTimeout(), 75);
EXPECT_EQ(getMaxSessionsPerMinute(), 0u);
EXPECT_EQ(getNumOfNginxIpcElements(), 200u);
EXPECT_EQ(getKeepAliveIntervalMsec(), 10000u);
EXPECT_EQ(getResProccessingTimeout(), 420u);
EXPECT_EQ(getReqProccessingTimeout(), 42u);
EXPECT_EQ(getRegistrationThreadTimeout(), 101u);
EXPECT_EQ(getReqHeaderThreadTimeout(), 10u);
EXPECT_EQ(getReqBodyThreadTimeout(), 155u);
EXPECT_EQ(getResHeaderThreadTimeout(), 1u);
EXPECT_EQ(getResBodyThreadTimeout(), 0u);
EXPECT_EQ(getMinRetriesForVerdict(), 1u);
EXPECT_EQ(getMaxRetriesForVerdict(), 3u);
EXPECT_EQ(getReqBodySizeTrigger(), 777u);
EXPECT_EQ(getWaitingForVerdictThreadTimeout(), 75u);
EXPECT_EQ(getInspectionMode(), ngx_http_inspection_mode::BLOCKING_THREAD);
EXPECT_EQ(isDebugContext("1.2.3.4", "5.6.7.8", 80, "GET", "test", "/abc"), 1);

View File

@@ -44,8 +44,11 @@ while true; do
done
if [ -z $var_token ] && [ $var_mode != "--hybrid_mode" ]; then
echo "Error: Token was not provided as input argument."
exit 1
var_token=$(env | grep 'AGENT_TOKEN=' | cut -d'=' -f2-)
if [ -z $var_token ]; then
echo "Error: Token was not provided as input argument."
exit 1
fi
fi
orchestration_service_installation_flags="--container_mode --skip_registration"

File diff suppressed because one or more lines are too long

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

@@ -42,6 +42,7 @@ HttpAttachmentConfig::init()
setNumOfNginxIpcElements();
setDebugByContextValues();
setKeepAliveIntervalMsec();
setRetriesForVerdict();
}
bool
@@ -215,6 +216,31 @@ HttpAttachmentConfig::setFailOpenTimeout()
conf_data.setNumericalValue("nginx_inspection_mode", inspection_mode);
}
void
HttpAttachmentConfig::setRetriesForVerdict()
{
conf_data.setNumericalValue("min_retries_for_verdict", getAttachmentConf<uint>(
3,
"agent.minRetriesForVerdict.nginxModule",
"HTTP manager",
"Min retries for verdict"
));
conf_data.setNumericalValue("max_retries_for_verdict", getAttachmentConf<uint>(
15,
"agent.maxRetriesForVerdict.nginxModule",
"HTTP manager",
"Max retries for verdict"
));
conf_data.setNumericalValue("body_size_trigger", getAttachmentConf<uint>(
200000,
"agent.reqBodySizeTrigger.nginxModule",
"HTTP manager",
"Request body size trigger"
));
}
void
HttpAttachmentConfig::setFailOpenWaitMode()
{

View File

@@ -70,6 +70,8 @@ private:
void setDebugByContextValues();
void setRetriesForVerdict();
WebTriggerConf web_trigger_conf;
HttpAttachmentConfiguration conf_data;
};

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

@@ -24,7 +24,8 @@ class ExternalSdkServer
:
public Component,
Singleton::Provide<I_ExternalSdkServer>,
Singleton::Consume<I_RestApi>
Singleton::Consume<I_RestApi>,
Singleton::Consume<I_Messaging>
{
public:
ExternalSdkServer();

View File

@@ -89,7 +89,9 @@ private:
bool matchAttributesRegEx(const std::set<std::string> &values,
std::set<std::string> &matched_override_keywords) const;
bool matchAttributesString(const std::set<std::string> &values) const;
bool matchAttributesIp(const std::set<std::string> &values) const;
bool isRegEx() const;
bool isIP() const;
MatchType type;
Operators operator_type;

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

@@ -26,6 +26,8 @@ static const map<string, IPSConfiguration::Context> default_conf_mapping = {
};
static const IPSConfiguration default_conf(default_conf_mapping);
static const IPSSignatures default_ips_sigs;
static const SnortSignatures default_snort_sigs;
IPSEntry::IPSEntry() : TableOpaqueSerialize<IPSEntry>(this) {}
@@ -51,9 +53,9 @@ IPSEntry::respond(const ParsedContext &parsed)
ctx.registerValue(name, buf);
ctx.activate();
auto &signatures = getConfigurationWithDefault(IPSSignatures(), "IPS", "IpsProtections");
auto &signatures = getConfigurationWithDefault(default_ips_sigs, "IPS", "IpsProtections");
bool should_drop = signatures.isMatchedPrevent(parsed.getName(), buf);
auto &snort_signatures = getConfigurationWithDefault(SnortSignatures(), "IPSSnortSigs", "SnortProtections");
auto &snort_signatures = getConfigurationWithDefault(default_snort_sigs, "IPSSnortSigs", "SnortProtections");
should_drop |= snort_signatures.isMatchedPrevent(parsed.getName(), buf);
ctx.deactivate();

View File

@@ -7,7 +7,7 @@ TEST(configuration, basic_context)
IPSConfiguration::Context ctx1(IPSConfiguration::ContextType::HISTORY, 254);
EXPECT_EQ(ctx1.getType(), IPSConfiguration::ContextType::HISTORY);
EXPECT_EQ(ctx1.getHistorySize(), 254);
EXPECT_EQ(ctx1.getHistorySize(), 254u);
IPSConfiguration::Context ctx2(IPSConfiguration::ContextType::NORMAL, 0);
EXPECT_EQ(ctx2.getType(), IPSConfiguration::ContextType::NORMAL);
@@ -42,7 +42,7 @@ TEST(configuration, read_configuration)
auto body = conf.getContext("HTTP_REQUEST_BODY");
EXPECT_EQ(body.getType(), IPSConfiguration::ContextType::HISTORY);
EXPECT_EQ(conf.getHistorySize("HTTP_REQUEST_BODY"), 100);
EXPECT_EQ(conf.getHistorySize("HTTP_REQUEST_BODY"), 100u);
auto header = conf.getContext("HTTP_REQUEST_HEADER");
EXPECT_EQ(header.getType(), IPSConfiguration::ContextType::KEEP);

View File

@@ -137,8 +137,8 @@ private:
TEST_F(EntryTest, basic_inherited_functions)
{
EXPECT_EQ(IPSEntry::name(), "IPS");
EXPECT_EQ(IPSEntry::currVer(), 0);
EXPECT_EQ(IPSEntry::minVer(), 0);
EXPECT_EQ(IPSEntry::currVer(), 0u);
EXPECT_EQ(IPSEntry::minVer(), 0u);
EXPECT_NE(IPSEntry::prototype(), nullptr);
EXPECT_EQ(entry.getListenerName(), IPSEntry::name());

View File

@@ -71,7 +71,7 @@ TEST(resources, basic_resource)
Singleton::Consume<Config::I_Config>::from(conf)->loadConfiguration(resource);
auto loaded_resources = getSettingWithDefault(IPSSignaturesResource(), "IPS", "protections");
EXPECT_EQ(loaded_resources.getSignatures().size(), 2);
EXPECT_EQ(loaded_resources.getSignatures().size(), 2u);
auto version = getSettingWithDefault<string>("", "IPS", "VersionId");
EXPECT_EQ(version, "1234567");
}

View File

@@ -385,8 +385,29 @@ Layer7AccessControl::Impl::init()
i_intelligence = Singleton::Consume<I_Intelligence_IS_V2>::by<Layer7AccessControl>();
i_mainloop = Singleton::Consume<I_MainLoop>::by<Layer7AccessControl>();
chrono::minutes expiration(
getProfileAgentSettingWithDefault<uint>(60u, "layer7AccessControl.crowdsec.cacheExpiration")
int cache_expiration_in_seconds = 30;
string cache_expiration_env = getenv("CROWDSEC_CACHE_EXPIRATION") ? getenv("CROWDSEC_CACHE_EXPIRATION") : "";
if (!cache_expiration_env.empty()) {
if (
all_of(cache_expiration_env.begin(), cache_expiration_env.end(), ::isdigit)
&& stoi(cache_expiration_env) > 0
) {
cache_expiration_in_seconds = stoi(cache_expiration_env);
dbgInfo(D_L7_ACCESS_CONTROL)
<< "Successfully read cache expiration value from env: "
<< cache_expiration_env;
} else {
dbgWarning(D_L7_ACCESS_CONTROL)
<< "An invalid cache expiration value was provided in env: "
<< cache_expiration_env;
}
}
chrono::seconds expiration(
getProfileAgentSettingWithDefault<uint>(
cache_expiration_in_seconds,
"layer7AccessControl.crowdsec.cacheExpiration"
)
);
ip_reputation_cache.startExpiration(

View File

@@ -247,7 +247,9 @@ Layer7AccessControlTest::verifyReport(
string log = reportToStr(report);
dbgTrace(D_L7_ACCESS_CONTROL) << "Report: " << log;
if (!source_identifier.empty()) EXPECT_THAT(log, HasSubstr("\"httpSourceId\": \"" + source_identifier + "\""));
if (!source_identifier.empty()) {
EXPECT_THAT(log, HasSubstr("\"httpSourceId\": \"" + source_identifier + "\""));
}
EXPECT_THAT(log, HasSubstr("\"securityAction\": \"" + security_action + "\""));
EXPECT_THAT(log, HasSubstr("\"eventName\": \"Access Control External Vendor Reputation\""));
EXPECT_THAT(log, HasSubstr("\"httpHostName\": \"juice-shop.checkpoint.com\""));

View File

@@ -404,6 +404,7 @@ AppsecPracticeAntiBotSection::save(cereal::JSONOutputArchive &out_ar) const
}
// LCOV_EXCL_START Reason: no test exist
// Used for V1Beta1
WebAppSection::WebAppSection(
const string &_application_urls,
const string &_asset_id,
@@ -417,7 +418,7 @@ WebAppSection::WebAppSection(
const LogTriggerSection &parsed_log_trigger,
const string &default_mode,
const AppSecTrustedSources &parsed_trusted_sources,
const vector<InnerException> &parsed_exceptions)
const std::map<std::string, std::vector<InnerException>> &exceptions)
:
application_urls(_application_urls),
asset_id(_asset_id),
@@ -449,8 +450,11 @@ WebAppSection::WebAppSection(
overrides.push_back(AppSecOverride(source_ident));
}
for (const InnerException &exception : parsed_exceptions) {
overrides.push_back(AppSecOverride(exception));
for (const auto &exception : exceptions) {
for (const auto &inner_exception : exception.second) {
overrides.push_back(AppSecOverride(inner_exception));
}
}
}

View File

@@ -146,7 +146,9 @@ AppsecException::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec exception";
parseAppsecJSONKey<string>("name", name, archive_in);
archive_in(CEREAL_NVP(exception_spec));
AppsecExceptionSpec single_exception_spec;
single_exception_spec.load(archive_in);
exception_spec.push_back(single_exception_spec);
}
void
@@ -174,7 +176,7 @@ ExceptionMatch::ExceptionMatch(const AppsecExceptionSpec &parsed_exception)
{
bool single_condition = parsed_exception.isOneCondition();
for (auto &attrib : attributes) {
auto &attrib_name = attrib.first;
auto attrib_name = (attrib.first == "sourceIp" ? "sourceIP" : attrib.first);
auto &attrib_getter = attrib.second;
auto exceptions_value = attrib_getter(parsed_exception);
if (exceptions_value.empty()) continue;

View File

@@ -275,7 +275,7 @@ public:
const LogTriggerSection &parsed_log_trigger,
const std::string &default_mode,
const AppSecTrustedSources &parsed_trusted_sources,
const std::vector<InnerException> &parsed_exceptions
const std::map<std::string, std::vector<InnerException>> &exceptions
);
// used for V1beta2

View File

@@ -44,7 +44,7 @@ public:
bool isOneCondition() const;
private:
int conditions_number;
int conditions_number = 0;
std::string action;
std::vector<std::string> country_code;
std::vector<std::string> country_name;

View File

@@ -79,6 +79,7 @@ class DefaultBackend
{
public:
void load(cereal::JSONInputArchive &);
bool doesExist() const;
private:
bool is_exists = false;
@@ -90,6 +91,7 @@ public:
void load(cereal::JSONInputArchive &archive_in);
const std::vector<IngressDefinedRule> & getRules() const;
bool doesDefaultBackendExist() const;
private:
std::string ingress_class_name;

View File

@@ -129,7 +129,7 @@ public:
bool shouldBeautifyLogs() const;
bool getCloud() const;
bool isK8SNeeded() const;
bool isContainerNeeded() const;
bool isCefNeeded() const;
bool isSyslogNeeded() const;
const std::string & getSyslogServerIpv4Address() const;
@@ -140,7 +140,7 @@ private:
const NewLoggingService & getCefServiceData() const;
bool cloud = false;
bool k8s_service = false;
bool container_service = false;
bool agent_local = true;
bool beautify_logs = true;
NewLoggingService syslog_service;

View File

@@ -111,7 +111,7 @@ private:
SecurityAppsWrapper security_apps;
};
class PolicyMakerUtils
class PolicyMakerUtils : Singleton::Consume<I_EnvDetails>
{
public:
std::string proccesSingleAppsecPolicy(

View File

@@ -39,7 +39,7 @@ public:
bool _logToAgent,
bool _logToCef,
bool _logToCloud,
bool _logToK8sService,
bool _logToContainerService,
bool _logToSyslog,
bool _responseBody,
bool _tpDetect,
@@ -73,7 +73,7 @@ private:
bool logToAgent;
bool logToCef;
bool logToCloud;
bool logToK8sService;
bool logToContainerService;
bool logToSyslog;
bool responseBody;
bool tpDetect;
@@ -258,7 +258,7 @@ public:
bool shouldBeautifyLogs() const;
bool getCloud() const;
bool isK8SNeeded() const;
bool isContainerNeeded() const;
bool isCefNeeded() const;
bool isSyslogNeeded() const;
const std::string & getSyslogServerIpv4Address() const;
@@ -269,7 +269,7 @@ private:
const LoggingService & getCefServiceData() const;
bool cloud = false;
bool k8s_service = false;
bool container_service = false;
bool agent_local = true;
bool beautify_logs = true;
LoggingService syslog_service;

View File

@@ -86,6 +86,12 @@ DefaultBackend::load(cereal::JSONInputArchive &)
is_exists = true;
}
bool
DefaultBackend::doesExist() const
{
return is_exists;
}
void
IngressSpec::load(cereal::JSONInputArchive &archive_in)
{
@@ -101,6 +107,12 @@ IngressSpec::getRules() const
return rules;
}
bool
IngressSpec::doesDefaultBackendExist() const
{
return default_backend.doesExist();
}
void
SingleIngressData::load(cereal::JSONInputArchive &archive_in)
{

View File

@@ -532,25 +532,37 @@ K8sPolicyUtils::createPolicy(
map<AnnotationKeys, string> &annotations_values,
const SingleIngressData &item) const
{
if (policies.find(annotations_values[AnnotationKeys::PolicyKey]) == policies.end()) {
policies[annotations_values[AnnotationKeys::PolicyKey]] = appsec_policy;
}
if (item.getSpec().doesDefaultBackendExist()) {
dbgTrace(D_LOCAL_POLICY)
<< "Inserting Any host rule to the specific asset set";
K ingress_rule = K("*");
policies[annotations_values[AnnotationKeys::PolicyKey]].addSpecificRule(ingress_rule);
}
for (const IngressDefinedRule &rule : item.getSpec().getRules()) {
string url = rule.getHost();
string host = rule.getHost();
for (const IngressRulePath &uri : rule.getPathsWrapper().getRulePaths()) {
if (!appsec_policy.getAppsecPolicySpec().isAssetHostExist(url + uri.getPath())) {
if (uri.getPath() != "/") {
host = host + uri.getPath();
}
if (!appsec_policy.getAppsecPolicySpec().isAssetHostExist(host)) {
dbgTrace(D_LOCAL_POLICY)
<< "Inserting Host data to the specific asset set:"
<< "URL: '"
<< url
<< rule.getHost()
<< "' uri: '"
<< uri.getPath()
<< "'";
K ingress_rule = K(url + uri.getPath());
appsec_policy.addSpecificRule(ingress_rule);
K ingress_rule = K(host);
policies[annotations_values[AnnotationKeys::PolicyKey]].addSpecificRule(ingress_rule);
}
}
}
policies[annotations_values[AnnotationKeys::PolicyKey]] = appsec_policy;
}
}
std::tuple<map<string, AppsecLinuxPolicy>, map<string, V1beta2AppsecLinuxPolicy>>
K8sPolicyUtils::createAppsecPoliciesFromIngresses()

View File

@@ -126,6 +126,7 @@ NewAppsecPolicySpec::load(cereal::JSONInputArchive &archive_in)
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec policy spec";
parseAppsecJSONKey<string>("appsecClassName", appsec_class_name, archive_in);
parseAppsecJSONKey<NewParsedRule>("default", default_rule, archive_in);
default_rule.setHost("*");
parseAppsecJSONKey<vector<NewParsedRule>>("specificRules", specific_rules, archive_in);
}

View File

@@ -183,7 +183,9 @@ NewAppsecTriggerLogDestination::load(cereal::JSONInputArchive &archive_in)
auto mode = Singleton::Consume<I_AgentDetails>::by<NewAppsecTriggerLogDestination>()->getOrchestrationMode();
auto env_type = Singleton::Consume<I_EnvDetails>::by<NewAppsecTriggerLogDestination>()->getEnvType();
bool k8s_service_default = (mode == OrchestrationMode::HYBRID && env_type == EnvType::K8S);
parseAppsecJSONKey<bool>("k8s-service", k8s_service, archive_in, k8s_service_default);
// BC try load previous name. TODO: update CRD
parseAppsecJSONKey<bool>("k8s-service", container_service, archive_in, k8s_service_default);
parseAppsecJSONKey<bool>("container-service", container_service, archive_in, container_service);
NewStdoutLogging stdout_log;
parseAppsecJSONKey<NewStdoutLogging>("stdout", stdout_log, archive_in);
@@ -224,9 +226,9 @@ NewAppsecTriggerLogDestination::getCloud() const
}
bool
NewAppsecTriggerLogDestination::isK8SNeeded() const
NewAppsecTriggerLogDestination::isContainerNeeded() const
{
return k8s_service;
return container_service;
}
bool

View File

@@ -21,6 +21,7 @@
using namespace std;
USE_DEBUG_FLAG(D_NGINX_POLICY);
USE_DEBUG_FLAG(D_LOCAL_POLICY);
void
SecurityAppsWrapper::save(cereal::JSONOutputArchive &out_ar) const
@@ -185,6 +186,33 @@ PolicyMakerUtils::dumpPolicyToFile(
return policy_str;
}
template<class R>
vector<string>
extractExceptionAnnotationNames(
const R &parsed_rule,
const R &default_rule,
const string &policy_name)
{
vector<string> annotation_names;
const R &rule = (!parsed_rule.getExceptions().empty() ? parsed_rule : default_rule);
for (const string &exception_name : rule.getExceptions()) {
if (exception_name.empty()) {
continue;
}
const auto policy_exception = policy_name + "/" + exception_name;
dbgTrace(D_NGINX_POLICY) << "Adding " << policy_exception << " to exception vector";
annotation_names.push_back(policy_exception);
}
dbgTrace(D_NGINX_POLICY) << "Number of exceptions related to rule: " << annotation_names.size();
return annotation_names;
}
template<class R>
map<AnnotationTypes, string>
extractAnnotationsNames(
@@ -217,18 +245,6 @@ extractAnnotationsNames(
rule_annotation[AnnotationTypes::TRIGGER] = policy_name + "/" + trigger_annotation_name;
}
string exception_annotation_name;
// TBD: support multiple exceptions
if (!parsed_rule.getExceptions().empty() && !parsed_rule.getExceptions()[0].empty()) {
exception_annotation_name = parsed_rule.getExceptions()[0];
} else if (!default_rule.getExceptions().empty() && !default_rule.getExceptions()[0].empty()) {
exception_annotation_name = default_rule.getExceptions()[0];
}
if (!exception_annotation_name.empty()) {
rule_annotation[AnnotationTypes::EXCEPTION] = policy_name + "/" + exception_annotation_name;
}
string web_user_res_annotation_name =
parsed_rule.getCustomResponse().empty() ?
default_rule.getCustomResponse() :
@@ -444,6 +460,7 @@ template<class T, class R>
R
getAppsecExceptionSpec(const string &exception_annotation_name, const T &policy)
{
dbgFlow(D_NGINX_POLICY) << "anotation name: " << exception_annotation_name;
auto exceptions_vec = policy.getAppsecExceptions();
auto exception_it = extractElement(exceptions_vec.begin(), exceptions_vec.end(), exception_annotation_name);
@@ -538,7 +555,7 @@ extractLogTriggerData(const string &trigger_annotation_name, const T &trigger_sp
bool webHeaders = trigger_spec.getAppsecTriggerExtendedLogging().isHttpHeaders();
bool webBody = trigger_spec.getAppsecTriggerExtendedLogging().isRequestBody();
bool logToCloud = trigger_spec.getAppsecTriggerLogDestination().getCloud();
bool logToK8sService = trigger_spec.getAppsecTriggerLogDestination().isK8SNeeded();
bool logToContainerService = trigger_spec.getAppsecTriggerLogDestination().isContainerNeeded();
bool logToAgent = trigger_spec.getAppsecTriggerLogDestination().isAgentLocal();
bool beautify_logs = trigger_spec.getAppsecTriggerLogDestination().shouldBeautifyLogs();
bool logToCef = trigger_spec.getAppsecTriggerLogDestination().isCefNeeded();
@@ -565,7 +582,7 @@ extractLogTriggerData(const string &trigger_annotation_name, const T &trigger_sp
logToAgent,
logToCef,
logToCloud,
logToK8sService,
logToContainerService,
logToSyslog,
responseBody,
tpDetect,
@@ -776,6 +793,7 @@ createExceptionSection(
const string &exception_annotation_name,
const T &policy)
{
dbgFlow(D_NGINX_POLICY) << "exception annotation name" << exception_annotation_name;
AppsecException exception_spec =
getAppsecExceptionSpec<T, AppsecException>(exception_annotation_name, policy);
vector<InnerException> res;
@@ -784,6 +802,7 @@ createExceptionSection(
ExceptionBehavior exception_behavior(exception.getAction());
res.push_back(InnerException(exception_behavior, exception_match));
}
return res;
}
@@ -896,13 +915,16 @@ createMultiRulesSections(
const string &web_user_res_vec_id,
const string &web_user_res_vec_type,
const string &asset_name,
const string &exception_name,
const vector<InnerException> &exceptions)
const std::map<std::string, std::vector<InnerException>> &exceptions)
{
PracticeSection practice = PracticeSection(practice_id, practice_type, practice_name);
vector<ParametersSection> exceptions_result;
for (auto exception : exceptions) {
exceptions_result.push_back(ParametersSection(exception.getBehaviorId(), exception_name));
const auto &exception_name = exception.first;
for (const auto &inner_exception : exception.second) {
exceptions_result.push_back(ParametersSection(inner_exception.getBehaviorId(), exception_name));
}
}
vector<RulesTriggerSection> triggers;
@@ -1344,6 +1366,7 @@ PolicyMakerUtils::combineElementsToPolicy(const string &policy_version)
convertMapToVector(log_triggers), convertMapToVector(web_user_res_triggers)
)
);
ExceptionsWrapper exceptions_section({
ExceptionsRulebase(convertExceptionsMapToVector(inner_exceptions))
});
@@ -1381,6 +1404,7 @@ PolicyMakerUtils::createPolicyElementsByRule(
const string &policy_name)
{
map<AnnotationTypes, string> rule_annotations = extractAnnotationsNames(rule, default_rule, policy_name);
if (
!rule_annotations[AnnotationTypes::TRIGGER].empty() &&
!log_triggers.count(rule_annotations[AnnotationTypes::TRIGGER])
@@ -1403,15 +1427,27 @@ PolicyMakerUtils::createPolicyElementsByRule(
);
}
if (
!rule_annotations[AnnotationTypes::EXCEPTION].empty() &&
!inner_exceptions.count(rule_annotations[AnnotationTypes::EXCEPTION])
) {
inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]] =
createExceptionSection<T>(
rule_annotations[AnnotationTypes::EXCEPTION],
policy
);
const auto exceptions_annotations = extractExceptionAnnotationNames(rule, default_rule, policy_name);
std::map<std::string, std::vector<InnerException>> rule_inner_exceptions;
if (!exceptions_annotations.empty()) {
for (const auto &exception_name :exceptions_annotations) {
dbgWarning(D_LOCAL_POLICY) << "exceptions name: " << exception_name;
if (rule_inner_exceptions.count(exception_name)) {
dbgWarning(D_LOCAL_POLICY) << "exception name already exists for that rule: " << exception_name;
continue;
}
if (inner_exceptions.count(exception_name)) {
dbgWarning(D_LOCAL_POLICY) << "exception name already exists in inner exceptions: " << exception_name;
rule_inner_exceptions[exception_name] = inner_exceptions[exception_name];
continue;
}
auto exception_section = createExceptionSection<T>(exception_name, policy);
rule_inner_exceptions[exception_name] = exception_section;
inner_exceptions[exception_name] = exception_section;
}
}
if (
@@ -1470,8 +1506,7 @@ PolicyMakerUtils::createPolicyElementsByRule(
web_user_res_triggers[rule_annotations[AnnotationTypes::WEB_USER_RES]].getTriggerId(),
"WebUserResponse",
full_url,
rule_annotations[AnnotationTypes::EXCEPTION],
inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]]
rule_inner_exceptions
);
rules_config[rule_config.getAssetName()] = rule_config;
@@ -1498,7 +1533,7 @@ PolicyMakerUtils::createPolicyElementsByRule(
log_triggers[rule_annotations[AnnotationTypes::TRIGGER]],
rule.getMode(),
trusted_sources[rule_annotations[AnnotationTypes::TRUSTED_SOURCES]],
inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]]
rule_inner_exceptions
);
web_apps[rule_config.getAssetName()] = web_app;
}
@@ -1636,7 +1671,9 @@ PolicyMakerUtils::createAgentPolicyFromAppsecPolicy(const string &policy_name, c
createPolicyElements<T, R>(specific_rules, default_rule, appsec_policy, policy_name);
// add default rule to policy
createPolicyElementsByRule<T, R>(default_rule, default_rule, appsec_policy, policy_name);
if (Singleton::Consume<I_EnvDetails>::by<PolicyMakerUtils>()->getEnvType() != EnvType::K8S) {
createPolicyElementsByRule<T, R>(default_rule, default_rule, appsec_policy, policy_name);
}
}
// LCOV_EXCL_START Reason: no test exist
@@ -1659,11 +1696,13 @@ PolicyMakerUtils::createAgentPolicyFromAppsecPolicy<V1beta2AppsecLinuxPolicy, Ne
);
// add default rule to policy
createPolicyElementsByRule<V1beta2AppsecLinuxPolicy, NewParsedRule>(
default_rule,
default_rule,
appsec_policy,
policy_name);
if (Singleton::Consume<I_EnvDetails>::by<PolicyMakerUtils>()->getEnvType() != EnvType::K8S) {
createPolicyElementsByRule<V1beta2AppsecLinuxPolicy, NewParsedRule>(
default_rule,
default_rule,
appsec_policy,
policy_name);
}
}
// LCOV_EXCL_STOP

View File

@@ -30,7 +30,7 @@ LogTriggerSection::LogTriggerSection(
bool _logToAgent,
bool _logToCef,
bool _logToCloud,
bool _logToK8sService,
bool _logToContainerService,
bool _logToSyslog,
bool _responseBody,
bool _tpDetect,
@@ -55,7 +55,7 @@ LogTriggerSection::LogTriggerSection(
logToAgent(_logToAgent),
logToCef(_logToCef),
logToCloud(_logToCloud),
logToK8sService(_logToK8sService),
logToContainerService(_logToContainerService),
logToSyslog(_logToSyslog),
responseBody(_responseBody),
tpDetect(_tpDetect),
@@ -96,12 +96,12 @@ LogTriggerSection::save(cereal::JSONOutputArchive &out_ar) const
cereal::make_nvp("acDrop", acDrop),
cereal::make_nvp("complianceViolations", false),
cereal::make_nvp("complianceWarnings", false),
cereal::make_nvp("extendloggingMinSeverity", extendloggingMinSeverity),
cereal::make_nvp("extendlogging", extendlogging),
cereal::make_nvp("extendLoggingMinSeverity", extendloggingMinSeverity),
cereal::make_nvp("extendLogging", extendlogging),
cereal::make_nvp("logToAgent", logToAgent),
cereal::make_nvp("logToCef", logToCef),
cereal::make_nvp("logToCloud", logToCloud),
cereal::make_nvp("logToK8sService", logToK8sService),
cereal::make_nvp("logToContainerService", logToContainerService),
cereal::make_nvp("logToSyslog", logToSyslog),
cereal::make_nvp("responseBody", responseBody),
cereal::make_nvp("responseCode", false),
@@ -396,7 +396,9 @@ AppsecTriggerLogDestination::load(cereal::JSONInputArchive &archive_in)
auto mode = Singleton::Consume<I_AgentDetails>::by<AppsecTriggerLogDestination>()->getOrchestrationMode();
auto env_type = Singleton::Consume<I_EnvDetails>::by<AppsecTriggerLogDestination>()->getEnvType();
bool k8s_service_default = (mode == OrchestrationMode::HYBRID && env_type == EnvType::K8S);
parseAppsecJSONKey<bool>("k8s-service", k8s_service, archive_in, k8s_service_default);
// BC try load previous name. TODO: update CRD
parseAppsecJSONKey<bool>("k8s-service", container_service, archive_in, k8s_service_default);
parseAppsecJSONKey<bool>("container-service", container_service, archive_in, container_service);
StdoutLogging stdout_log;
parseAppsecJSONKey<StdoutLogging>("stdout", stdout_log, archive_in);
@@ -437,9 +439,9 @@ AppsecTriggerLogDestination::getCloud() const
}
bool
AppsecTriggerLogDestination::isK8SNeeded() const
AppsecTriggerLogDestination::isContainerNeeded() const
{
return k8s_service;
return container_service;
}
bool

View File

@@ -12,6 +12,9 @@ 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(external_sdk_server)
#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;
@@ -142,7 +142,7 @@ DetailsResolver::Impl::isCloudStorageEnabled()
{
auto cloud_storage_mode_override = getProfileAgentSetting<bool>("agent.cloudStorage.enabled");
if (cloud_storage_mode_override.ok()) {
dbgInfo(D_ORCHESTRATOR) << "Received cloud-storage mode override: " << *cloud_storage_mode_override;
dbgDebug(D_ORCHESTRATOR) << "Received cloud-storage mode override: " << *cloud_storage_mode_override;
return *cloud_storage_mode_override;
}
@@ -152,6 +152,7 @@ DetailsResolver::Impl::isCloudStorageEnabled()
bool
DetailsResolver::Impl::isKernelVersion3OrHigher()
{
#if defined(gaia) || defined(smb)
static const string cmd =
"clish -c 'show version os kernel' | awk '{print $4}' "
"| cut -d '.' -f 1 | awk -F: '{ if ( $1 >= 3 ) {print 1} else {print 0}}'";
@@ -160,12 +161,14 @@ DetailsResolver::Impl::isKernelVersion3OrHigher()
if (is_gogo.ok() && !is_gogo.unpack().empty()) {
return is_gogo.unpack().front() == '1';
}
#endif
return false;
}
bool
DetailsResolver::Impl::isGwNotVsx()
{
#if defined(gaia) || defined(smb)
static const string is_gw_cmd = "cpprod_util FwIsFirewallModule";
static const string is_vsx_cmd = "cpprod_util FWisVSX";
auto is_gw = DetailsResolvingHanlder::getCommandOutput(is_gw_cmd);
@@ -173,6 +176,7 @@ DetailsResolver::Impl::isGwNotVsx()
if (is_gw.ok() && is_vsx.ok() && !is_gw.unpack().empty() && !is_vsx.unpack().empty()) {
return is_gw.unpack().front() == '1' && is_vsx.unpack().front() == '0';
}
#endif
return false;
}
@@ -300,19 +304,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 +358,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

@@ -24,14 +24,16 @@
Maybe<string>
checkSAMLSupportedBlade(const string &command_output)
{
string supportedBlades[3] = {"identityServer", "vpn", "cvpn"};
// uncomment when vpn will support SAML authentication
// string supportedBlades[3] = {"identityServer", "vpn", "cvpn"};
string supportedBlades[1] = {"identityServer"};
for(const string &blade : supportedBlades) {
if (command_output.find(blade) != string::npos) {
return string("true");
}
}
return genError("Current host does not have SAML capability");
return string("false");
}
Maybe<string>
@@ -42,7 +44,7 @@ checkIDABlade(const string &command_output)
return string("true");
}
return genError("Current host does not have IDA installed");
return string("false");
}
Maybe<string>
@@ -52,33 +54,26 @@ checkSAMLPortal(const string &command_output)
return string("true");
}
return genError("Current host does not have SAML Portal configured");
return string("false");
}
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 string("false");
}
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>
@@ -94,7 +89,7 @@ checkIDP(shared_ptr<istream> file_stream)
}
}
return genError("Identity Provider was not found");
return string("false");
}
#endif // gaia

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

@@ -99,6 +99,7 @@ map<string, string>
DetailsResolvingHanlder::Impl::getResolvedDetails() const
{
I_ShellCmd *shell = Singleton::Consume<I_ShellCmd>::by<DetailsResolvingHanlder>();
I_AgentDetailsReporter *reporter = Singleton::Consume<I_AgentDetailsReporter>::by<DetailsResolvingHanlder>();
uint32_t timeout = getConfigurationWithDefault<uint32_t>(5000, "orchestration", "Details resolver time out");
for (auto &shell_pre_command : shell_pre_commands) {
@@ -122,7 +123,15 @@ DetailsResolvingHanlder::Impl::getResolvedDetails() const
Maybe<string> shell_command_output = getCommandOutput(command);
if (!shell_command_output.ok()) continue;
Maybe<string> handler_ret = handler(*shell_command_output);
if (handler_ret.ok()) resolved_details[attr] = *handler_ret;
if (handler_ret.ok()) {
resolved_details[attr] = *handler_ret;
} else {
if (reporter->isPersistantAttr(attr)) {
dbgTrace(D_AGENT_DETAILS)<< "Persistent attribute changed, removing old value";
reporter->deleteAttr(attr);
}
}
}
for (auto file_handler : file_content_handlers) {
@@ -133,7 +142,7 @@ DetailsResolvingHanlder::Impl::getResolvedDetails() const
shared_ptr<ifstream> in_file =
Singleton::Consume<I_OrchestrationTools>::by<DetailsResolvingHanlder>()->fileStreamWrapper(path);
if (!in_file->is_open()) {
dbgWarning(D_AGENT_DETAILS) << "Could not open file for processing. Path: " << path;
dbgDebug(D_AGENT_DETAILS) << "Could not open file for processing. Path: " << path;
continue;
}
@@ -157,7 +166,6 @@ DetailsResolvingHanlder::Impl::getResolvedDetails() const
}
}
I_AgentDetailsReporter *reporter = Singleton::Consume<I_AgentDetailsReporter>::by<DetailsResolvingHanlder>();
reporter->addAttr(resolved_details, true);
return resolved_details;

View File

@@ -1,3 +1,7 @@
#include <sstream>
class Package;
static std::ostream & operator<<(std::ostream &os, const Package &) { return os; }
#include "cptest.h"
#include "config.h"
#include "config_component.h"

View File

@@ -0,0 +1,4 @@
include_directories(${PROJECT_SOURCE_DIR}/core/external_sdk/)
add_library(external_sdk_server external_sdk_server.cc)
add_subdirectory(external_sdk_server_ut)

View File

@@ -0,0 +1,348 @@
#include "external_sdk_server.h"
#include "external_agent_sdk.h"
#include "log_generator.h"
#include "rest_server.h"
#include "generic_metric.h"
#include "customized_cereal_map.h"
#include "report/log_rest.h"
using namespace std;
USE_DEBUG_FLAG(D_EXTERNAL_SDK_USER);
USE_DEBUG_FLAG(D_EXTERNAL_SDK_SERVER);
class ExternalSdkRest : public ServerRest
{
public:
void
doCall() override
{
dbgFlow(D_EXTERNAL_SDK_SERVER);
Maybe<SdkApiType> sdk_event_type = convertToEnum<SdkApiType>(event_type.get());
if (!sdk_event_type.ok()) {
dbgWarning(D_EXTERNAL_SDK_SERVER) << "Received illegal event type. Type : " << event_type.get();
throw JsonError("Illegal event type provided");
}
dbgDebug(D_EXTERNAL_SDK_SERVER)
<< "Handling a new external sdk api call event. Type : "
<< convertApiTypeToString(sdk_event_type.unpack());
I_ExternalSdkServer *sdk_server = Singleton::Consume<I_ExternalSdkServer>::from<ExternalSdkServer>();
switch(sdk_event_type.unpack()) {
case SdkApiType::SendCodeEvent: {
if (!file.isActive()) {
throw JsonError("File was not provided for code event");
}
if (!func.isActive()) {
throw JsonError("Function was not provided for code event");
}
if (!line.isActive()) {
throw JsonError("Line path was not provided for code event");
}
if (!trace_id.isActive()) {
throw JsonError("Trace ID was not provided for code event");
}
if (!span_id.isActive()) {
throw JsonError("Span ID was not provided for code event");
}
if (!message.isActive()) {
throw JsonError("Message was not provided for code event");
}
sdk_server->sendDebug(
file.get(),
func.get(),
line.get(),
getDebugLevel(),
trace_id.get(),
span_id.get(),
message.get(),
additional_fields.isActive() ? additional_fields.get() : map<string, string>()
);
return;
}
case SdkApiType::SendEventDrivenEvent: {
if (!event_name.isActive()) {
throw JsonError("Event name was not provided for event");
}
sdk_server->sendLog(
event_name.get(),
getAudience(),
getSeverity(),
getPriority(),
tag.get(),
additional_fields.isActive() ? additional_fields.get() : map<string, string>()
);
return;
}
case SdkApiType::SendGetConfigRequest: {
if (!config_path.isActive()) {
throw JsonError("Config path was not provided for get configuration event");
}
Maybe<string> config_val = sdk_server->getConfigValue(config_path.get());
config_value = config_val.ok() ? config_val.unpack() : "";
return;
}
case SdkApiType::SendPeriodicEvent: {
if (!event_name.isActive()) {
throw JsonError("Event name was not provided for periodic event");
}
if (!service_name.isActive()) {
throw JsonError("Service name was not provided for periodic event");
}
sdk_server->sendMetric(
event_name,
service_name,
getAudienceTeam(),
ReportIS::IssuingEngine::AGENT_CORE,
additional_fields.isActive() ? additional_fields.get() : map<string, string>()
);
return;
}
default: {
dbgError(D_EXTERNAL_SDK_SERVER) << "Received illegal event type. Type : " << event_type.get();
}
}
}
private:
static string
convertApiTypeToString(SdkApiType type)
{
static const EnumArray<SdkApiType, string> api_type_string {
"Code Event",
"Periodic Event",
"Event Driven",
"Get Configuration",
};
return api_type_string[type];
}
Debug::DebugLevel
getDebugLevel()
{
static const map<int, Debug::DebugLevel> debug_levels = {
{0, Debug::DebugLevel::TRACE},
{1, Debug::DebugLevel::DEBUG},
{2, Debug::DebugLevel::INFO},
{3, Debug::DebugLevel::WARNING},
{4, Debug::DebugLevel::ERROR}
};
if (!debug_level.isActive()) {
throw JsonError("Debug level was not provided for code event");
}
auto level = debug_levels.find(debug_level.get());
if(level == debug_levels.end()) {
throw JsonError("Illegal debug level provided");
}
return level->second;
}
ReportIS::Severity
getSeverity()
{
if (!severity.isActive()) {
throw JsonError("Event severity was not provided for periodic event");
}
switch (severity.get()) {
case EventSeverity::SeverityCritical: return ReportIS::Severity::CRITICAL;
case EventSeverity::SeverityHigh: return ReportIS::Severity::HIGH;
case EventSeverity::SeverityMedium: return ReportIS::Severity::MEDIUM;
case EventSeverity::SeverityLow: return ReportIS::Severity::LOW;
case EventSeverity::SeverityInfo: return ReportIS::Severity::INFO;
default:
throw JsonError("Illegal event severity provided");
}
}
ReportIS::Priority
getPriority()
{
if (!priority.isActive()) {
throw JsonError("Event priority was not provided");
}
switch (priority.get()) {
case EventPriority::PriorityUrgent: return ReportIS::Priority::URGENT;
case EventPriority::PriorityHigh: return ReportIS::Priority::HIGH;
case EventPriority::PriorityMedium: return ReportIS::Priority::MEDIUM;
case EventPriority::PriorityLow: return ReportIS::Priority::LOW;
default:
throw JsonError("Illegal event priority provided");
}
}
ReportIS::Audience
getAudience()
{
if (!audience.isActive()) {
throw JsonError("Event audience was not provided");
}
switch (audience.get()) {
case EventAudience::AudienceSecurity: return ReportIS::Audience::SECURITY;
case EventAudience::AudienceInternal: return ReportIS::Audience::INTERNAL;
default:
throw JsonError("Illegal event audience provided");
}
}
ReportIS::AudienceTeam
getAudienceTeam()
{
if (!team.isActive()) {
throw JsonError("Event audience team was not provided");
}
switch (team.get()) {
case EventAudienceTeam::AudienceTeamAgentCore: return ReportIS::AudienceTeam::AGENT_CORE;
case EventAudienceTeam::AudienceTeamIot: return ReportIS::AudienceTeam::IOT_NEXT;
case EventAudienceTeam::AudienceTeamWaap: return ReportIS::AudienceTeam::WAAP;
case EventAudienceTeam::AudienceTeamAgentIntelligence: return ReportIS::AudienceTeam::AGENT_INTELLIGENCE;
default:
throw JsonError("Illegal event audience team provided");
}
}
using additional_fields_map = map<string, string>;
C2S_LABEL_PARAM(int, event_type, "eventType");
C2S_LABEL_OPTIONAL_PARAM(additional_fields_map, additional_fields, "additionalFields");
C2S_LABEL_OPTIONAL_PARAM(string, event_name, "eventName");
C2S_LABEL_OPTIONAL_PARAM(string, service_name, "serviceName");
C2S_OPTIONAL_PARAM(int, team);
C2S_OPTIONAL_PARAM(int, audience);
C2S_OPTIONAL_PARAM(int, severity);
C2S_OPTIONAL_PARAM(int, priority);
C2S_OPTIONAL_PARAM(string, tag);
C2S_OPTIONAL_PARAM(string, file);
C2S_OPTIONAL_PARAM(string, func);
C2S_OPTIONAL_PARAM(int, line);
C2S_LABEL_OPTIONAL_PARAM(int, debug_level, "debugLevel");
C2S_LABEL_OPTIONAL_PARAM(string, trace_id, "traceId");
C2S_LABEL_OPTIONAL_PARAM(string, span_id, "spanId");
C2S_OPTIONAL_PARAM(string, message);
C2S_LABEL_OPTIONAL_PARAM(string, config_path, "configPath");
S2C_LABEL_OPTIONAL_PARAM(string, config_value, "configValue");
};
class ExternalSdkServer::Impl
:
public Singleton::Provide<I_ExternalSdkServer>::From<ExternalSdkServer>
{
public:
void
init()
{
auto rest = Singleton::Consume<I_RestApi>::by<ExternalSdkServer>();
rest->addRestCall<ExternalSdkRest>(RestAction::ADD, "sdk-call");
}
void
sendLog(
const string &event_name,
ReportIS::Audience audience,
ReportIS::Severity severity,
ReportIS::Priority priority,
const string &tag_string,
const map<string, string> &additional_fields)
{
Maybe<ReportIS::Tags> tag = TagAndEnumManagement::convertStringToTag(tag_string);
set<ReportIS::Tags> tags;
if (tag.ok()) tags.insert(tag.unpack());
LogGen log(event_name, audience, severity, priority, tags);
for (const auto &field : additional_fields) {
log << LogField(field.first, field.second);
}
}
void
sendDebug(
const string &file_name,
const string &function_name,
unsigned int line_number,
Debug::DebugLevel debug_level,
const string &trace_id,
const string &span_id,
const string &message,
const map<string, string> &additional_fields)
{
(void)trace_id;
(void)span_id;
Debug debug(file_name, function_name, line_number, debug_level, D_EXTERNAL_SDK_USER);
debug.getStreamAggr() << message;
bool is_first_key = true;
for (const auto &field : additional_fields) {
if (is_first_key) {
is_first_key = false;
debug.getStreamAggr() << ". ";
} else {
debug.getStreamAggr() << ", ";
}
debug.getStreamAggr() << "\"" << field.first << "\": \"" << field.second << "\"";
}
}
void
sendMetric(
const string &event_title,
const string &service_name,
ReportIS::AudienceTeam team,
ReportIS::IssuingEngine issuing_engine,
const map<string, string> &additional_fields)
{
ScopedContext ctx;
ctx.registerValue("Service Name", service_name);
set<ReportIS::Tags> tags;
Report metric_to_fog(
event_title,
Singleton::Consume<I_TimeGet>::by<GenericMetric>()->getWalltime(),
ReportIS::Type::PERIODIC,
ReportIS::Level::LOG,
ReportIS::LogLevel::INFO,
ReportIS::Audience::INTERNAL,
team,
ReportIS::Severity::INFO,
ReportIS::Priority::LOW,
chrono::seconds(0),
LogField("agentId", Singleton::Consume<I_AgentDetails>::by<GenericMetric>()->getAgentId()),
tags,
ReportIS::Tags::INFORMATIONAL,
issuing_engine
);
for (const auto &field : additional_fields) {
metric_to_fog << LogField(field.first, field.second);
}
LogRest metric_client_rest(metric_to_fog);
string fog_metric_uri = getConfigurationWithDefault<string>("/api/v1/agents/events", "metric", "fogMetricUri");
Singleton::Consume<I_Messaging>::by<ExternalSdkServer>()->sendAsyncMessage(
HTTPMethod::POST,
fog_metric_uri,
metric_client_rest,
MessageCategory::METRIC,
MessageMetadata(),
false
);
}
Maybe<string>
getConfigValue(const string &config_path)
{
auto config_val = getProfileAgentSetting<string>(config_path);
if (!config_val.ok()) {
stringstream error;
error << "Failed to get configuration. Config path: " << config_path << ", Error: " << config_val.getErr();
return genError(error.str());
}
return config_val.unpack();
}
};
ExternalSdkServer::ExternalSdkServer() : Component("ExternalSdkServer"), pimpl(make_unique<Impl>()) {}
ExternalSdkServer::~ExternalSdkServer() {}
void ExternalSdkServer::init() { pimpl->init(); }
void ExternalSdkServer::fini() {}
void ExternalSdkServer::preload() {}

View File

@@ -0,0 +1,7 @@
link_directories(${BOOST_ROOT}/lib)
add_unit_test(
external_sdk_server_ut
"external_sdk_server_ut.cc"
"external_sdk_server;mainloop;singleton;rest;environment;time_proxy;logging;event_is;metric;-lboost_context;agent_details;-lboost_regex;messaging;"
)

View File

@@ -0,0 +1,349 @@
#include <stdio.h>
#include <stdarg.h>
#include "external_sdk_server.h"
#include "cptest.h"
#include "mock/mock_rest_api.h"
#include "mock/mock_messaging.h"
#include "mock/mock_logging.h"
#include "mock/mock_time_get.h"
#include "config.h"
#include "config_component.h"
#include "agent_details.h"
using namespace std;
using namespace testing;
class ExternalSdkServerTest : public Test
{
public:
ExternalSdkServerTest()
{
EXPECT_CALL(rest_mocker, mockRestCall(RestAction::ADD, "sdk-call", _)).WillOnce(
WithArg<2>(
Invoke(
[this](const unique_ptr<RestInit> &rest_ptr)
{
mock_sdk_rest = rest_ptr->getRest();
return true;
}
)
)
);
sdk_server.preload();
sdk_server.init();
i_sdk = Singleton::Consume<I_ExternalSdkServer>::from(sdk_server);
}
~ExternalSdkServerTest()
{
sdk_server.fini();
}
ExternalSdkServer sdk_server;
NiceMock<MockTimeGet> mock_timer;
StrictMock<MockMessaging> messaging_mocker;
StrictMock<MockRestApi> rest_mocker;
StrictMock<MockLogging> log_mocker;
unique_ptr<ServerRest> mock_sdk_rest;
I_ExternalSdkServer *i_sdk;
ConfigComponent conf;
AgentDetails agent_details;
::Environment env;
};
TEST_F(ExternalSdkServerTest, initTest)
{
}
TEST_F(ExternalSdkServerTest, configCall)
{
Maybe<string> no_conf = i_sdk->getConfigValue("key1");
EXPECT_FALSE(no_conf.ok());
string config_json =
"{\n"
"\"agentSettings\": [\n"
"{\n"
"\"id\": \"id1\",\n"
"\"key\": \"key1\",\n"
"\"value\": \"value1\"\n"
"},\n"
"{\n"
"\"id\": \"id1\",\n"
"\"key\": \"key2\",\n"
"\"value\": \"value2\"\n"
"}\n"
"]\n"
"}\n";
conf.preload();
istringstream conf_stream(config_json);
ASSERT_TRUE(Singleton::Consume<Config::I_Config>::from(conf)->loadConfiguration(conf_stream));
Maybe<string> conf_found = i_sdk->getConfigValue("key1");
ASSERT_TRUE(conf_found.ok());
EXPECT_EQ(conf_found.unpack(), "value1");
conf_found = i_sdk->getConfigValue("key2");
ASSERT_TRUE(conf_found.ok());
EXPECT_EQ(conf_found.unpack(), "value2");
stringstream config_call_body;
config_call_body << "{ \"eventType\": 3, \"configPath\": \"key1\" }";
Maybe<string> sdk_conf = mock_sdk_rest->performRestCall(config_call_body);
ASSERT_TRUE(sdk_conf.ok());
EXPECT_EQ(
sdk_conf.unpack(),
"{\n"
" \"configValue\": \"value1\"\n"
"}"
);
}
template <typename T>
string
toJson(const T &obj)
{
stringstream ss;
{
cereal::JSONOutputArchive ar(ss);
obj.serialize(ar);
}
return ss.str();
}
TEST_F(ExternalSdkServerTest, eventDrivenCall)
{
string generated_log;
EXPECT_CALL(log_mocker, getCurrentLogId()).Times(2).WillRepeatedly(Return(0));
EXPECT_CALL(log_mocker, sendLog(_)).Times(2).WillRepeatedly(
WithArg<0>(
Invoke(
[&] (const Report &msg)
{
generated_log = toJson(msg);
}
)
)
);
i_sdk->sendLog(
"my log",
ReportIS::Audience::INTERNAL,
ReportIS::Severity::LOW,
ReportIS::Priority::HIGH,
"IPS",
{{"key1", "value1"}, {"key2", "value2"}}
);
static const string expected_log =
"{\n"
" \"eventTime\": \"\",\n"
" \"eventName\": \"my log\",\n"
" \"eventSeverity\": \"Low\",\n"
" \"eventPriority\": \"High\",\n"
" \"eventType\": \"Event Driven\",\n"
" \"eventLevel\": \"Log\",\n"
" \"eventLogLevel\": \"info\",\n"
" \"eventAudience\": \"Internal\",\n"
" \"eventAudienceTeam\": \"\",\n"
" \"eventFrequency\": 0,\n"
" \"eventTags\": [\n"
" \"IPS\"\n"
" ],\n"
" \"eventSource\": {\n"
" \"agentId\": \"Unknown\",\n"
" \"eventTraceId\": \"\",\n"
" \"eventSpanId\": \"\",\n"
" \"issuingEngineVersion\": \"\",\n"
" \"serviceName\": \"Unnamed Nano Service\"\n"
" },\n"
" \"eventData\": {\n"
" \"logIndex\": 0,\n"
" \"key1\": \"value1\",\n"
" \"key2\": \"value2\"\n"
" }\n"
"}";
EXPECT_EQ(generated_log, expected_log);
string event_call_body =
"{\n"
" \"eventType\": 2,\n"
" \"eventName\": \"my log\",\n"
" \"audience\": 1,\n"
" \"severity\": 3,\n"
" \"priority\": 1,\n"
" \"tag\": \"IPS\",\n"
" \"team\": 3,\n"
" \"additionalFields\": {\n"
" \"key1\": \"value1\",\n"
" \"key2\": \"value2\"\n"
" }\n"
"}";
generated_log = "";
stringstream event_call_stream;
event_call_stream << event_call_body;
EXPECT_TRUE(mock_sdk_rest->performRestCall(event_call_stream).ok());
EXPECT_EQ(generated_log, expected_log);
}
TEST_F(ExternalSdkServerTest, periodicEventCall)
{
string message_body;
EXPECT_CALL(
messaging_mocker,
sendAsyncMessage(
HTTPMethod::POST,
"/api/v1/agents/events",
_,
MessageCategory::METRIC,
_,
false
)
).Times(2).WillRepeatedly(SaveArg<2>(&message_body));
i_sdk->sendMetric(
"my metric",
"matrix",
ReportIS::AudienceTeam::AGENT_INTELLIGENCE,
ReportIS::IssuingEngine::AGENT_CORE,
{{"key", "value"}}
);
static const string expected_message =
"{\n"
" \"log\": {\n"
" \"eventTime\": \"\",\n"
" \"eventName\": \"my metric\",\n"
" \"eventSeverity\": \"Info\",\n"
" \"eventPriority\": \"Low\",\n"
" \"eventType\": \"Periodic\",\n"
" \"eventLevel\": \"Log\",\n"
" \"eventLogLevel\": \"info\",\n"
" \"eventAudience\": \"Internal\",\n"
" \"eventAudienceTeam\": \"Agent Intelligence\",\n"
" \"eventFrequency\": 0,\n"
" \"eventTags\": [\n"
" \"Informational\"\n"
" ],\n"
" \"eventSource\": {\n"
" \"agentId\": \"Unknown\",\n"
" \"issuingEngine\": \"Agent Core\",\n"
" \"eventTraceId\": \"\",\n"
" \"eventSpanId\": \"\",\n"
" \"issuingEngineVersion\": \"\",\n"
" \"serviceName\": \"matrix\"\n"
" },\n"
" \"eventData\": {\n"
" \"key\": \"value\"\n"
" }\n"
" }\n"
"}";
EXPECT_EQ(message_body, expected_message);
string event_call_body =
"{\n"
" \"eventType\": 1,\n"
" \"eventName\": \"my metric\",\n"
" \"serviceName\": \"matrix\",\n"
" \"team\": 3,\n"
" \"additionalFields\": {\n"
" \"key\": \"value\"\n"
" }\n"
"}";
stringstream event_call_stream;
event_call_stream << event_call_body;
message_body = "";
EXPECT_TRUE(mock_sdk_rest->performRestCall(event_call_stream).ok());
EXPECT_EQ(message_body, expected_message);
}
USE_DEBUG_FLAG(D_EXTERNAL_SDK_USER);
USE_DEBUG_FLAG(D_EXTERNAL_SDK_SERVER);
TEST_F(ExternalSdkServerTest, codeEventCall)
{
ostringstream capture_debug;
Debug::setUnitTestFlag(D_EXTERNAL_SDK_SERVER, Debug::DebugLevel::TRACE);
Debug::setUnitTestFlag(D_EXTERNAL_SDK_USER, Debug::DebugLevel::TRACE);
Debug::setNewDefaultStdout(&capture_debug);
i_sdk->sendDebug(
"file.cc",
"myFunc2",
42,
Debug::DebugLevel::TRACE,
"123",
"abc",
"h#l1ow w0r!d",
{{"hi", "universe"}}
);
EXPECT_THAT(
capture_debug.str(),
HasSubstr(
"[myFunc2@file.cc:42 | >>>] "
"h#l1ow w0r!d. \"hi\": \"universe\"\n"
)
);
string debug_event =
"{\n"
" \"eventType\": 0,\n"
" \"file\": \"my file\",\n"
" \"func\": \"function_name\",\n"
" \"line\": 42,\n"
" \"debugLevel\": 0,\n"
" \"traceId\": \"\",\n"
" \"spanId\": \"span2323\",\n"
" \"message\": \"some short debug\",\n"
" \"team\": 1,\n"
" \"additionalFields\": {\n"
" \"name\": \"moshe\",\n"
" \"food\": \"bamba\"\n"
" }\n"
"}";
stringstream event_call_stream;
event_call_stream << debug_event;
EXPECT_TRUE(mock_sdk_rest->performRestCall(event_call_stream).ok());
EXPECT_THAT(
capture_debug.str(),
HasSubstr(
"[function_name@my file:42 | >>>] "
"some short debug. \"food\": \"bamba\", \"name\": \"moshe\"\n"
)
);
Debug::setNewDefaultStdout(&cout);
}
TEST_F(ExternalSdkServerTest, ilegalEventCall)
{
string event_call_body =
"{\n"
" \"eventType\": 7,\n"
" \"eventName\": \"my metric\",\n"
" \"serviceName\": \"matrix\",\n"
" \"team\": 3,\n"
" \"additionalFields\": {\n"
" \"key\": \"value\"\n"
" }\n"
"}";
stringstream event_call_stream;
event_call_stream << event_call_body;
Maybe<string> failed_respond = mock_sdk_rest->performRestCall(event_call_stream);
EXPECT_FALSE(failed_respond.ok());
EXPECT_EQ(failed_respond.getErr(), "Illegal event type provided");
}

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

@@ -51,6 +51,7 @@ public:
private:
I_DeclarativePolicy *i_declarative_policy = nullptr;
std::string profile_mode;
};
#endif // __FOG_COMMUNICATION_H__

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,135 @@
// 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,
SERVISE_CONFIGURATION,
SERVISE_CONFIGURATION_TIMEOUT,
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::SERVISE_CONFIGURATION : return "SERVISE_CONFIGURATION";
case UpdatesFailureReason::SERVISE_CONFIGURATION_TIMEOUT : return "SERVISE_CONFIGURATION_TIMEOUT";
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;
std::string getDescriptionWithoutErrors() const;
private:
UpdatesProcessResult result;
UpdatesConfigType type;
UpdatesFailureReason reason;
std::string detail;
std::string description;
};
#endif // __UPDATES_PROCESS_EVENT_H__

View File

@@ -0,0 +1,63 @@
// 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();
}
UpdatesFailureReason getReason() const { return reason; }
private:
UpdatesProcessResult result;
UpdatesConfigType type;
UpdatesFailureReason reason;
std::string description;
std::string time_stamp;
};
#endif // __UPDATES_PROCESS_EVENT_H__

View File

@@ -0,0 +1,44 @@
// 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 "i_service_controller.h"
#include "health_check_status/health_check_status.h"
#include "updates_process_event.h"
#include "updates_process_report.h"
class UpdatesProcessReporter
:
public Listener<UpdatesProcessEvent>,
Singleton::Consume<I_ServiceController>
{
public:
void upon(const UpdatesProcessEvent &event) override;
private:
void sendReoprt(const std::string &version);
static std::vector<UpdatesProcessReport> reports;
std::map<std::string, uint> report_failure_count_map;
};
#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

@@ -1,3 +1,7 @@
#include <sstream>
class Package;
static std::ostream & operator<<(std::ostream &os, const Package &) { return os; }
#include "manifest_controller.h"
#include <vector>
@@ -281,13 +285,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 +708,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 +926,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 +998,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 +1388,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 +2516,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 +2561,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 +2574,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

@@ -43,8 +43,8 @@ TEST_F(PolicyTest, serialization)
ASSERT_TRUE(false) << "Cereal threw an exception: " << e.what();
}
EXPECT_EQ(15, orchestration_policy.getErrorSleepInterval());
EXPECT_EQ(20, orchestration_policy.getSleepInterval());
EXPECT_EQ(15u, orchestration_policy.getErrorSleepInterval());
EXPECT_EQ(20u, orchestration_policy.getSleepInterval());
EXPECT_EQ("http://10.0.0.18:81/control/", orchestration_policy.getFogAddress());
}
@@ -63,8 +63,8 @@ TEST_F(PolicyTest, noAgentType)
ASSERT_TRUE(false) << "Cereal threw an exception: " << e.what();
}
EXPECT_EQ(15, orchestration_policy.getErrorSleepInterval());
EXPECT_EQ(20, orchestration_policy.getSleepInterval());
EXPECT_EQ(15u, orchestration_policy.getErrorSleepInterval());
EXPECT_EQ(20u, orchestration_policy.getSleepInterval());
EXPECT_EQ("http://10.0.0.18:81/control/", orchestration_policy.getFogAddress());
}
@@ -83,8 +83,8 @@ TEST_F(PolicyTest, zeroSleepIntervels)
ASSERT_TRUE(false) << "Cereal threw an exception: " << e.what();
}
EXPECT_EQ(0, orchestration_policy.getErrorSleepInterval());
EXPECT_EQ(0, orchestration_policy.getSleepInterval());
EXPECT_EQ(0u, orchestration_policy.getErrorSleepInterval());
EXPECT_EQ(0u, orchestration_policy.getSleepInterval());
EXPECT_EQ("http://10.0.0.18:81/control/", orchestration_policy.getFogAddress());
}
@@ -152,7 +152,7 @@ TEST_F(PolicyTest, newOptionalFields)
ASSERT_TRUE(false) << "Cereal threw an exception: " << e.what();
}
EXPECT_EQ(10, orchestration_policy.getErrorSleepInterval());
EXPECT_EQ(30, orchestration_policy.getSleepInterval());
EXPECT_EQ(10u, orchestration_policy.getErrorSleepInterval());
EXPECT_EQ(30u, orchestration_policy.getSleepInterval());
EXPECT_EQ("https://fog-api-gw-agents.cloud.ngen.checkpoint.com", orchestration_policy.getFogAddress());
}

View File

@@ -1,3 +1,7 @@
#include <sstream>
class Package;
static std::ostream & operator<<(std::ostream &os, const Package &) { return os; }
#include "orchestration_status.h"
#include <string>
@@ -13,6 +17,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 +205,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 +500,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.",
"Failed. Reason: " + manifest_error
),
result
);
}

View File

@@ -1,3 +1,7 @@
#include <sstream>
class Package;
static std::ostream & operator<<(std::ostream &os, const Package &) { return os; }
#include "url_parser.h"
#include "cptest.h"

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,17 @@ public:
},
"Write Orchestration status file"
);
registerListener();
}
void
upon(const UpdatesProcessEvent &event) override
{
setFieldStatus(
event.getStatusFieldType(),
event.getOrchestrationStatusResult(),
event.getDescriptionWithoutErrors()
);
}
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)
@@ -1481,7 +1499,7 @@ private:
<< " minutes from now.";
upgrade_delay_time += chrono::minutes(upgrade_delay_interval);
} catch (const exception& err) {
dbgInfo(D_ORCHESTRATOR) << "Failed to parse upgrade delay interval.";
dbgWarning(D_ORCHESTRATOR) << "Failed to parse upgrade delay interval.";
}
}
@@ -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

@@ -1,3 +1,7 @@
#include <sstream>
class Package;
std::ostream & operator<<(std::ostream &os, const Package &) { return os; }
#include "orchestration_comp.h"
#include "cptest.h"
@@ -144,7 +148,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 +288,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));
@@ -471,6 +475,9 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource)
)
).WillOnce(Return(Maybe<void>()));
string version = "1";
EXPECT_CALL(mock_service_controller, getUpdatePolicyVersion()).WillOnce(ReturnRef(version));
EXPECT_CALL(
mock_service_controller,
updateServiceConfiguration(

View File

@@ -1,3 +1,7 @@
#include <sstream>
class Package;
std::ostream & operator<<(std::ostream &os, const Package &) { return os; }
#include "orchestration_comp.h"
#include "cptest.h"
@@ -22,6 +26,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 +104,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 +176,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 +363,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,9 +382,12 @@ 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(_));
string version = "1";
EXPECT_CALL(mock_service_controller, getUpdatePolicyVersion()).WillOnce(ReturnRef(version));
EXPECT_CALL(mock_ml, yield(A<chrono::microseconds>()))
.WillOnce(Return())
.WillOnce(Invoke([] (chrono::microseconds) { throw invalid_argument("stop while loop"); }));
@@ -584,9 +593,11 @@ 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(_));
string version = "1";
EXPECT_CALL(mock_service_controller, getUpdatePolicyVersion()).WillOnce(ReturnRef(version));
EXPECT_CALL(mock_ml, yield(A<chrono::microseconds>()))
.WillOnce(Return())
.WillOnce(Invoke([] (chrono::microseconds) { throw invalid_argument("stop while loop"); }));
@@ -718,6 +729,9 @@ TEST_F(OrchestrationTest, orchestrationPolicyUpdatRollback)
EXPECT_CALL(mock_status, setPolicyVersion(third_val));
EXPECT_CALL(mock_status, setPolicyVersion(second_val));
string version = "1";
EXPECT_CALL(mock_service_controller, getUpdatePolicyVersion()).WillOnce(ReturnRef(version));
string policy_versions;
EXPECT_CALL(mock_service_controller, getPolicyVersions()).WillRepeatedly(ReturnRef(policy_versions));
EXPECT_CALL(mock_update_communication, sendPolicyVersion("13", _)).Times(1).WillOnce(Return(Maybe<void>()));
@@ -761,10 +775,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(
@@ -899,6 +909,9 @@ TEST_F(OrchestrationTest, orchestrationPolicyUpdate)
);
EXPECT_CALL(mock_status, setPolicyVersion(third_val));
string version = "1";
EXPECT_CALL(mock_service_controller, getUpdatePolicyVersion()).WillOnce(ReturnRef(version));
string policy_versions;
EXPECT_CALL(mock_service_controller, getPolicyVersions()).WillRepeatedly(ReturnRef(policy_versions));
EXPECT_CALL(mock_update_communication, sendPolicyVersion("13", _)).Times(1).WillOnce(Return(Maybe<void>()));
@@ -940,10 +953,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 +1022,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 +1117,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(
@@ -1128,6 +1129,9 @@ TEST_F(OrchestrationTest, manifestUpdate)
)
);
string version = "1";
EXPECT_CALL(mock_service_controller, getUpdatePolicyVersion()).WillOnce(ReturnRef(version));
GetResourceFile manifest_file(GetResourceFile::ResourceFileType::MANIFEST);
EXPECT_CALL(mock_downloader,
downloadFile(
@@ -1166,6 +1170,8 @@ TEST_F(OrchestrationTest, manifestUpdate)
TEST_F(OrchestrationTest, getBadPolicyUpdate)
{
Debug::setUnitTestFlag(D_UPDATES_PROCESS_REPORTER, Debug::DebugLevel::NOISE);
EXPECT_CALL(
rest,
mockRestCall(RestAction::ADD, "proxy", _)
@@ -1212,6 +1218,13 @@ TEST_F(OrchestrationTest, getBadPolicyUpdate)
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::SHA256, data_file_path))
.WillOnce(Return(data_checksum));
string manifest = "";
string policy = "111111";
string setting = "";
string second_val = "12";
string third_val = "13";
EXPECT_CALL(mock_service_controller, getUpdatePolicyVersion()).WillRepeatedly(ReturnRef(third_val));
Maybe<string> new_policy_checksum(string("111111"));
GetResourceFile policy_file(GetResourceFile::ResourceFileType::POLICY);
@@ -1223,12 +1236,6 @@ TEST_F(OrchestrationTest, getBadPolicyUpdate)
policy_file
)
).WillOnce(Return(Maybe<std::string>(string(new_policy_path))));
string manifest = "";
string policy = "111111";
string setting = "";
string second_val = "12";
string third_val = "13";
EXPECT_CALL(mock_service_controller, getPolicyVersion())
.Times(4)
.WillOnce(ReturnRef(first_policy_version))
@@ -1237,10 +1244,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(
@@ -1266,12 +1269,10 @@ TEST_F(OrchestrationTest, getBadPolicyUpdate)
)
);
EXPECT_CALL(mock_service_controller, getUpdatePolicyVersion()).WillRepeatedly(ReturnRef(third_val));
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 +1329,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 +1361,13 @@ TEST_F(OrchestrationTest, failedDownloadSettings)
);
EXPECT_CALL(mock_status, setLastUpdateAttempt());
EXPECT_CALL(
mock_status,
setFieldStatus(OrchestrationStatusFieldType::LAST_UPDATE, OrchestrationStatusResult::SUCCESS, "")
).Times(1);
string version = "1";
EXPECT_CALL(mock_service_controller, getUpdatePolicyVersion()).WillOnce(ReturnRef(version));
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 +1468,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(
@@ -1491,6 +1480,10 @@ TEST_P(OrchestrationTest, orchestrationFirstRun)
}
)
);
string version = "1";
EXPECT_CALL(mock_service_controller, getUpdatePolicyVersion()).WillOnce(ReturnRef(version));
EXPECT_CALL(mock_service_controller, getPolicyVersion()).WillRepeatedly(ReturnRef(first_policy_version));
EXPECT_CALL(mock_update_communication, getUpdate(_)).WillOnce(
Invoke(
@@ -1537,23 +1530,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();
}
@@ -1706,6 +1682,10 @@ TEST_F(OrchestrationTest, dataUpdate)
.WillOnce(Return(data_instance_checksum));
EXPECT_CALL(mock_service_controller, getPolicyVersion()).WillRepeatedly(ReturnRef(first_policy_version));
string version = "1";
EXPECT_CALL(mock_service_controller, getUpdatePolicyVersion()).WillOnce(ReturnRef(version));
EXPECT_CALL(mock_update_communication, getUpdate(_)).WillOnce(
Invoke(
[&](CheckUpdateRequest &req)
@@ -1721,10 +1701,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

@@ -1,3 +1,7 @@
#include <sstream>
class Package;
static std::ostream & operator<<(std::ostream &os, const Package &) { return os; }
#include "package_handler.h"
#include "cptest.h"

View File

@@ -29,6 +29,7 @@
#include "i_orchestration_tools.h"
#include "customized_cereal_map.h"
#include "declarative_policy_utils.h"
#include "updates_process_event.h"
using namespace std;
using namespace ReportIS;
@@ -65,6 +66,13 @@ public:
}
if (error.get()) {
service_controller->updateReconfStatus(id.get(), service_name.get(), ReconfStatus::FAILED);
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::GENERAL,
UpdatesFailureReason::SERVISE_CONFIGURATION,
string(service_name.get() + ", ID: " + to_string(id.get())),
(error_message.isActive() ? " Error: " + error_message.get() : "")
).notify();
dbgError(D_SERVICE_CONTROLLER)
<< "Request for service reconfiguration failed to complete. ID: "
<< id.get()
@@ -333,7 +341,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 +366,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 +383,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();
}
@@ -407,7 +421,7 @@ ServiceController::Impl::getUpdatedReconfStatus()
}
if (!maybe_service.unpack().isServiceActive()) {
dbgInfo(D_SERVICE_CONTROLLER)
dbgDebug(D_SERVICE_CONTROLLER)
<< "Service is not active, removing from registered services list. Service: "
<< services_reconf_names[service_and_reconf_status.first]
<< "ID: "
@@ -500,8 +514,9 @@ 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)
dbgDebug(D_SERVICE_CONTROLLER)
<< "Orchestration pending services loaded from file."
<< " File: "
<< registered_services_file
@@ -509,7 +524,7 @@ ServiceController::Impl::loadRegisteredServicesFromFile()
for (const auto &id_service_pair : pending_services) {
const auto &service = id_service_pair.second;
dbgInfo(D_SERVICE_CONTROLLER)
dbgDebug(D_SERVICE_CONTROLLER)
<< "Service name: "
<< service.getServiceName()
<< ", Service ID: "
@@ -529,18 +544,26 @@ 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)
dbgDebug(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)
dbgDebug(D_SERVICE_CONTROLLER)
<< "Service name: "
<< service.getServiceName()
<< ", Service ID: "
@@ -591,20 +614,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 +647,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();
@@ -1007,6 +1036,12 @@ ServiceController::Impl::sendSignalForServices(
}
dbgDebug(D_SERVICE_CONTROLLER) << "The reconfiguration has reached a timeout";
UpdatesProcessEvent(
UpdatesProcessResult::FAILED,
UpdatesConfigType::GENERAL,
UpdatesFailureReason::SERVISE_CONFIGURATION_TIMEOUT,
"The reconfiguration has reached a timeout"
).notify();
services_reconf_status.clear();
services_reconf_names.clear();
return genError("The reconfiguration has reached a timeout");

View File

@@ -1,3 +1,7 @@
#include <sstream>
class Package;
static std::ostream & operator<<(std::ostream &os, const Package &) { return os; }
#include "cptest.h"
#include <string>
#include "orchestration_tools.h"
@@ -178,16 +182,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 +201,7 @@ public:
::Environment env;
ConfigComponent config;
DeclarativePolicyUtils declarative_policy_utils;
string version_body;
string configuration_dir;
string policy_extension;
string settings_extension;
@@ -229,19 +235,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 +346,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 +552,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 +598,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 +1615,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

@@ -1,2 +1 @@
add_library(update_communication update_communication.cc hybrid_communication.cc fog_communication.cc fog_authenticator.cc local_communication.cc declarative_policy_utils.cc fog_helper_open_source.cc)
#add_subdirectory(update_communication_ut)

View File

@@ -141,7 +141,7 @@ DeclarativePolicyUtils::sendUpdatesToFog(
auto shell_cmd = Singleton::Consume<I_ShellCmd>::by<DeclarativePolicyUtils>();
string exec_command =
getFilesystemPathConfig()
+ "/scripts/open-appsec-cloud-mgmt --upload_policy_only"
+ "/scripts/open-appsec-cloud-mgmt --config-upload-only"
+ " --access_token " + access_token
+ " --tenant_id " + tenant_id
+ " --profile_id " + profile_id;

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 @@ FogCommunication::init()
{
FogAuthenticator::init();
i_declarative_policy = Singleton::Consume<I_DeclarativePolicy>::from<DeclarativePolicyUtils>();
profile_mode = getSettingWithDefault<string>("management", "profileManagedMode");
}
Maybe<void>
@@ -66,6 +67,16 @@ FogCommunication::getUpdate(CheckUpdateRequest &request)
Maybe<string> maybe_new_data = request.getData();
string data_checksum = maybe_new_data.ok() ? maybe_new_data.unpack() : "";
if (profile_mode != policy_mgmt_mode) {
dbgTrace(D_ORCHESTRATOR)
<< "The profile managed mode was changed from: "
<< profile_mode
<< " to: "
<< policy_mgmt_mode;
profile_mode = policy_mgmt_mode;
i_declarative_policy->turnOnApplyPolicyFlag();
}
if (i_declarative_policy->shouldApplyPolicy()) {
string policy_response = i_declarative_policy->getUpdate(request);
if (!policy_response.empty()) {

View File

@@ -120,10 +120,9 @@ HybridCommunication::downloadAttributeFile(const GetResourceFile &resourse_file,
}
Maybe<void>
HybridCommunication::sendPolicyVersion(const string &policy_version, const string &) const
HybridCommunication::sendPolicyVersion(const string &, const string &) const
{
dbgFlow(D_ORCHESTRATOR);
policy_version.empty();
return Maybe<void>();
}

View File

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

View File

@@ -1,7 +0,0 @@
link_directories(${BOOST_ROOT}/lib)
add_unit_test(
update_communication_ut
"local_communication_ut.cc;fog_communication_ut.cc"
"rest;version;orchestration_modules;update_communication;singleton;config;metric;event_is;logging;agent_details;-lboost_regex;local_policy_mgmt_gen;connkey;"
)

View File

@@ -1,244 +0,0 @@
#include <string>
#include "local_communication.h"
#include "cptest.h"
#include "mock/mock_orchestration_tools.h"
#include "config.h"
#include "config_component.h"
#include "orchestration_status.h"
#include "mock/mock_mainloop.h"
#include "mock/mock_time_get.h"
using namespace std;
using namespace testing;
ostream &
operator<<(ostream &os, const tuple<OrchManifest, OrchPolicy, OrchSettings> &)
{
return os;
}
class LocalCommunicationTest: public Test
{
public:
LocalCommunicationTest()
{
local_communication.init();
}
void
preload()
{
local_communication.preload();
}
Maybe<void>
authenticateAgent()
{
return local_communication.authenticateAgent();
}
void
registerLocalAgentToFog()
{
local_communication.registerLocalAgentToFog();
}
Maybe<void>
sendPolicyVersion(const string &version, const string &policy_versions)
{
return local_communication.sendPolicyVersion(version, policy_versions);
}
Maybe<string>
downloadAttributeFile(const GetResourceFile &resourse_file, const string &file_path)
{
return local_communication.downloadAttributeFile(resourse_file, file_path);
}
void
setAddressExtenesion(const string &ext)
{
local_communication.setAddressExtenesion(ext);
}
Maybe<void>
checkUpdate(CheckUpdateRequest &request)
{
return local_communication.getUpdate(request);
}
NiceMock<MockMainLoop> mock_mainloop;
NiceMock<MockTimeGet> mock_timer;
::Environment env;
ConfigComponent config_comp;
StrictMock<MockOrchestrationTools> mock_orc_tools;
OrchestrationStatus orc_status;
private:
LocalCommunication local_communication;
};
TEST_F(LocalCommunicationTest, doNothing)
{
}
TEST_F(LocalCommunicationTest, registerConfig)
{
env.preload();
env.init();
preload();
string config_json =
"{\n"
" \"orchestration\": {\n"
" \"Offline manifest file path\": [\n"
" {\n"
" \"context\": \"All()\",\n"
" \"value\": \"ABC\"\n"
" }\n"
" ],\n"
" \"Offline policy file path\": [\n"
" {\n"
" \"context\": \"All()\",\n"
" \"value\": \"qwe\"\n"
" }\n"
" ],\n"
" \"Offline settings file path\": [\n"
" {\n"
" \"context\": \"All()\",\n"
" \"value\": \"CCCC\"\n"
" }\n"
" ]\n"
" }\n"
"}";
istringstream ss(config_json);
Singleton::Consume<Config::I_Config>::from(config_comp)->loadConfiguration(ss);
EXPECT_THAT(getConfiguration<string>("orchestration", "Offline manifest file path"), IsValue("ABC"));
EXPECT_THAT(getConfiguration<string>("orchestration", "Offline policy file path"), IsValue("qwe"));
EXPECT_THAT(getConfiguration<string>("orchestration", "Offline settings file path"), IsValue("CCCC"));
env.fini();
}
TEST_F(LocalCommunicationTest, authenticateAgent)
{
auto authenticat_res = authenticateAgent();
EXPECT_TRUE(authenticat_res.ok());
}
TEST_F(LocalCommunicationTest, registerLocalAgentToFog)
{
registerLocalAgentToFog();
}
TEST_F(LocalCommunicationTest, downloadManifest)
{
string new_manifest_string = "new manifest";
EXPECT_CALL(mock_orc_tools, readFile("/etc/cp/conf/offline_manifest.json")).WillOnce(Return(new_manifest_string));
GetResourceFile resourse_file(GetResourceFile::ResourceFileType::MANIFEST);
auto downloaded_string = downloadAttributeFile(resourse_file, "/tmp/orch_files");
EXPECT_TRUE(downloaded_string.ok());
EXPECT_EQ(downloaded_string.unpack(), new_manifest_string);
}
TEST_F(LocalCommunicationTest, checkUpdateWithNoUpdate)
{
Maybe<string> manifest_checksum(string("1"));
Maybe<string> policy_checksum(string("2"));
Maybe<string> settings_checksum(string("3"));
Maybe<string> data_checksum(string("4"));
EXPECT_CALL(mock_orc_tools, calculateChecksum(
Package::ChecksumTypes::SHA256, "/etc/cp/conf/offline_manifest.json")).WillOnce(Return(manifest_checksum));
EXPECT_CALL(mock_orc_tools, calculateChecksum(
Package::ChecksumTypes::SHA256, "/etc/cp/conf/offline_policy.json")).WillOnce(Return(policy_checksum));
EXPECT_CALL(mock_orc_tools, calculateChecksum(
Package::ChecksumTypes::SHA256, "/etc/cp/conf/offline_settings.json")).WillOnce(Return(settings_checksum));
EXPECT_CALL(mock_orc_tools, calculateChecksum(
Package::ChecksumTypes::SHA256, "/etc/cp/conf/data/offline_data.json")).WillOnce(Return(data_checksum));
CheckUpdateRequest request(
*manifest_checksum,
*policy_checksum,
*settings_checksum,
*data_checksum,
I_OrchestrationTools::SELECTED_CHECKSUM_TYPE_STR,
"123"
);
auto update_response = checkUpdate(request);
EXPECT_TRUE(update_response.ok());
Maybe<string> manifest = request.getManifest();
EXPECT_FALSE(manifest.ok());
Maybe<string> policy = request.getPolicy();
EXPECT_FALSE(policy.ok());
Maybe<string> settings = request.getSettings();
EXPECT_FALSE(settings.ok());
Maybe<string> data = request.getData();
EXPECT_FALSE(data.ok());
}
TEST_F(LocalCommunicationTest, checkUpdateWithPolicyUpdate)
{
Maybe<string> manifest_checksum(string("1"));
Maybe<string> policy_checksum(string("2"));
Maybe<string> new_policy_checksum(string("22"));
Maybe<string> settings_checksum(string("3"));
Maybe<string> data_checksum(string("4"));
EXPECT_CALL(
mock_orc_tools,
calculateChecksum(Package::ChecksumTypes::SHA256, "/etc/cp/conf/offline_manifest.json")
).WillOnce(Return(manifest_checksum));
EXPECT_CALL(
mock_orc_tools,
calculateChecksum(Package::ChecksumTypes::SHA256, "/etc/cp/conf/offline_policy.json")
).WillOnce(Return(new_policy_checksum));
EXPECT_CALL(
mock_orc_tools,
calculateChecksum(Package::ChecksumTypes::SHA256, "/etc/cp/conf/offline_settings.json")
).WillOnce(Return(settings_checksum));
EXPECT_CALL(
mock_orc_tools,
calculateChecksum(Package::ChecksumTypes::SHA256, "/etc/cp/conf/data/offline_data.json")
).WillOnce(Return(data_checksum));
CheckUpdateRequest request(
*manifest_checksum,
*policy_checksum,
*settings_checksum,
*data_checksum,
I_OrchestrationTools::SELECTED_CHECKSUM_TYPE_STR,
"123"
);
auto update_response = checkUpdate(request);
EXPECT_TRUE(update_response.ok());
Maybe<string> manifest = request.getManifest();
EXPECT_FALSE(manifest.ok());
EXPECT_THAT(request.getPolicy(), IsValue("22"));
Maybe<string> settings = request.getSettings();
EXPECT_FALSE(settings.ok());
Maybe<string> data = request.getData();
EXPECT_FALSE(data.ok());
}
TEST_F(LocalCommunicationTest, setAddressExtenesion)
{
setAddressExtenesion("Test");
}
TEST_F(LocalCommunicationTest, sendPolicyVersion)
{
auto res = sendPolicyVersion("12", "");
EXPECT_TRUE(res.ok());
}

View File

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

View File

@@ -0,0 +1,203 @@
// 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::SERVISE_CONFIGURATION : {
err
<< "Request for service reconfiguration failed to complete. Service name: "
<< detail
<< ". Error: "
<< description;
break;
}
case UpdatesFailureReason::SERVISE_CONFIGURATION_TIMEOUT : {
err << detail;
break;
}
case UpdatesFailureReason::ORCHESTRATION_SELF_UPDATE : {
err << description;
break;
}
case UpdatesFailureReason::NONE : {
err << description;
break;
}
}
return err.str();
}
string
UpdatesProcessEvent::getDescriptionWithoutErrors() 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.";
break;
}
case UpdatesFailureReason::GET_UPDATE_REQUEST: {
err << "Failed to get update request.";
break;
}
case UpdatesFailureReason::DOWNLOAD_FILE : {
err << "Failed to download the file " << detail;
break;
}
case UpdatesFailureReason::HANDLE_FILE : {
err << "Failed to handle the file " << detail;
break;
}
case UpdatesFailureReason::INSTALLATION_QUEUE : {
err << "Installation queue creation failed.";
break;
}
case UpdatesFailureReason::INSTALL_PACKAGE : {
err << "Failed to install the package " << detail;
break;
}
case UpdatesFailureReason::CHECKSUM_UNMATCHED : {
err << "Checksums do not match for the file: " << detail;
break;
}
case UpdatesFailureReason::POLICY_CONFIGURATION : {
err << "Failed to configure policy version: " << detail;
break;
}
case UpdatesFailureReason::POLICY_FOG_CONFIGURATION : {
err << "Failed to configure the fog address: " << detail;
break;
}
case UpdatesFailureReason::SERVISE_CONFIGURATION : {
err << "Request for service reconfiguration failed to complete. Service name: " << detail;
break;
}
case UpdatesFailureReason::SERVISE_CONFIGURATION_TIMEOUT : {
err << detail;
break;
}
case UpdatesFailureReason::ORCHESTRATION_SELF_UPDATE : {
err << description;
break;
}
case UpdatesFailureReason::NONE : {
err << description;
break;
}
}
return err.str();
}

View File

@@ -0,0 +1,94 @@
// 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) {
auto i_controller = Singleton::Consume<I_ServiceController>::by<UpdatesProcessReporter>();
string version = i_controller->getUpdatePolicyVersion();
if (event.getResult() == UpdatesProcessResult::SUCCESS && reports.empty()) {
dbgTrace(D_UPDATES_PROCESS_REPORTER) << "Update proccess finished successfully";
report_failure_count_map.erase(version);
return;
}
if (report_failure_count_map.find(version) == report_failure_count_map.end()) {
report_failure_count_map[version] = 0;
}
report_failure_count_map[version]++;
dbgTrace(D_UPDATES_PROCESS_REPORTER)
<< "Update proccess finished with errors. Count: "
<< report_failure_count_map[version];
if (report_failure_count_map[version] <= 1) {
reports.clear();
return;
}
reports.emplace_back(
UpdatesProcessReport(
event.getResult(),
event.getType(),
event.getReason(),
event.parseDescription()
)
);
sendReoprt(version);
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(const string &version)
{
stringstream full_reports;
UpdatesFailureReason failure_reason = UpdatesFailureReason::NONE;
full_reports << "Updates process reports:" << endl;
full_reports << "Policy version: " << version << endl;
full_reports << "report failure count:" << report_failure_count_map[version] << endl;
for (const auto &report : reports) {
if (report.getReason() != UpdatesFailureReason::CHECK_UPDATE) {
failure_reason = report.getReason();
}
full_reports << report.toString() << endl;
}
reports.clear();
dbgTrace(D_UPDATES_PROCESS_REPORTER) << "Sending updates process report: " << endl << full_reports.str();
LogGen log (
"Updates process report",
ReportIS::Audience::INTERNAL,
ReportIS::Severity::HIGH,
ReportIS::Priority::HIGH,
ReportIS::Tags::ORCHESTRATOR
);
log << LogField("eventMessage", full_reports.str());
if (failure_reason != UpdatesFailureReason::NONE) {
log.addToOrigin(LogField("eventCategory", convertUpdatesFailureReasonToStr(failure_reason)));
}
}

View File

@@ -57,7 +57,6 @@ private:
std::vector<std::string> filesPathsList;
};
class I_Serializable {
public:
virtual void serialize(std::ostream& stream) = 0;

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

@@ -23,6 +23,7 @@ unescaped_line(),
param_name(),
location(),
score(0.0f),
scoreNoFilter(0.0f),
scoreArray(),
keywordCombinations(),
attack_types(),
@@ -40,6 +41,7 @@ void Waf2ScanResult::clear()
param_name.clear();
location.clear();
score = 0;
scoreNoFilter = 0;
scoreArray.clear();
keywordCombinations.clear();
attack_types.clear();

View File

@@ -29,6 +29,7 @@ struct Waf2ScanResult {
std::string param_name;
std::string location;
double score;
double scoreNoFilter;
std::vector<double> scoreArray;
std::vector<std::string> keywordCombinations;
std::set<std::string> attack_types;

View File

@@ -397,7 +397,7 @@ SerializeToLocalAndRemoteSyncBase::SerializeToLocalAndRemoteSyncBase(
const string &owner
) :
SerializeToFileBase(filePath),
m_remotePath(remotePath),
m_remotePath(replaceAllCopy(remotePath, "//", "/")),
m_interval(0),
m_owner(owner),
m_pMainLoop(nullptr),
@@ -407,7 +407,7 @@ SerializeToLocalAndRemoteSyncBase::SerializeToLocalAndRemoteSyncBase(
m_windowsCount(0),
m_intervalsCounter(0),
m_remoteSyncEnabled(true),
m_assetId(assetId),
m_assetId(replaceAllCopy(assetId, "/", "")),
m_isAssetIdUuid(Waap::Util::isUuid(assetId)),
m_shared_storage_host(genError("not set")),
m_learning_host(genError("not set"))
@@ -439,7 +439,7 @@ SerializeToLocalAndRemoteSyncBase::SerializeToLocalAndRemoteSyncBase(
}
if (remotePath != "") {
// remote path is /<tenantId>/<assetId>/<type>
auto parts = split(remotePath, '/');
auto parts = split(m_remotePath, '/');
if (parts.size() > 2) {
size_t offset = 0;
if (parts[0].empty()) {
@@ -656,8 +656,7 @@ void SerializeToLocalAndRemoteSyncBase::syncWorker()
OrchestrationMode mode = Singleton::exists<I_AgentDetails>() ?
Singleton::Consume<I_AgentDetails>::by<WaapComponent>()->getOrchestrationMode() : OrchestrationMode::ONLINE;
if (mode == OrchestrationMode::OFFLINE || !m_remoteSyncEnabled || isBase() ||
(mode == OrchestrationMode::ONLINE && !m_isAssetIdUuid) || !postData()) {
if (mode == OrchestrationMode::OFFLINE || !m_remoteSyncEnabled || isBase() || !postData()) {
dbgDebug(D_WAAP_CONFIDENCE_CALCULATOR)
<< "Did not synchronize the data. for asset: "
<< m_assetId
@@ -727,7 +726,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

@@ -37,7 +37,14 @@ WaapTelemetryBase::sendLog(const LogRest &metric_client_rest) const
if (mode == OrchestrationMode::ONLINE) {
return;
}
auto svc_host = getConfigurationWithDefault(default_host, "Logging", "K8sSvc Log host");
const char* host_env_var = getenv("TUNING_HOST");
string host;
if (host_env_var != nullptr && strlen(host_env_var) > 0) {
host = string(host_env_var);
} else {
host = default_host;
}
auto svc_host = getConfigurationWithDefault(host, "Logging", "Container Log host");
string fog_metric_uri = getConfigurationWithDefault<string>("/api/v1/agents/events", "metric", "fogMetricUri");
MessageMetadata req_md(svc_host, 80);
req_md.insertHeader(

View File

@@ -15,6 +15,7 @@
#include "i_mainloop.h"
#include "i_serialize.h"
#include "waap.h"
#include "Waf2Util.h"
using namespace std;
@@ -25,7 +26,7 @@ USE_DEBUG_FLAG(D_WAAP);
TuningDecision::TuningDecision(const string& remotePath)
:
m_remotePath(remotePath + "/tuning"),
m_remotePath(replaceAllCopy(remotePath + "/tuning", "//", "/")),
m_baseUri()
{
if (remotePath == "")

View File

@@ -39,7 +39,7 @@ namespace Conversions {
return HIGH_THREAT;
}
bool shouldDoWafBlocking(const IWaapConfig* pWaapConfig, ThreatLevel threatLevel)
bool shouldDoWafBlocking(const IWaapConfig* const pWaapConfig, ThreatLevel threatLevel)
{
if (pWaapConfig == NULL)
{

View File

@@ -20,7 +20,7 @@
namespace Waap {
namespace Conversions {
ThreatLevel convertFinalScoreToThreatLevel(double finalScore);
bool shouldDoWafBlocking(const IWaapConfig* pSitePolicy, ThreatLevel threatLevel);
bool shouldDoWafBlocking(const IWaapConfig* const pSitePolicy, ThreatLevel threatLevel);
}
}

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

@@ -25,7 +25,7 @@ USE_DEBUG_FLAG(D_OA_SCHEMA_UPDATER);
// id generated by xml parser for an entity attribute
const std::string Waap::Scanner::xmlEntityAttributeId = "08a80340-06d3-11ea-9f87-0242ac11000f";
double Waap::Scanner::getScoreData(Waf2ScanResult& res, const std::string &poolName)
double Waap::Scanner::getScoreData(Waf2ScanResult& res, const std::string &poolName, bool applyLearning)
{
std::string source = m_transaction->getSourceIdentifier();
@@ -33,21 +33,24 @@ double Waap::Scanner::getScoreData(Waf2ScanResult& res, const std::string &poolN
Waap::Keywords::KeywordsSet keywordsSet;
Waap::Keywords::computeKeywordsSet(keywordsSet, res.keyword_matches, res.found_patterns);
std::string param_name = IndicatorsFiltersManager::generateKey(res.location, res.param_name, m_transaction);
dbgTrace(D_WAAP_SCANNER) << "filter processing for parameter: " << param_name;
m_transaction->getAssetState()->logIndicatorsInFilters(param_name, keywordsSet, m_transaction);
if (applyLearning) {
std::string param_name = IndicatorsFiltersManager::generateKey(res.location, res.param_name, m_transaction);
dbgTrace(D_WAAP_SCANNER) << "filter processing for parameter: " << param_name <<
", indicators count: " << keywordsSet.size();
m_transaction->getAssetState()->logIndicatorsInFilters(param_name, keywordsSet, m_transaction);
m_transaction->getAssetState()->filterKeywords(param_name, keywordsSet, res.filtered_keywords);
if (m_transaction->getSiteConfig() != nullptr)
{
auto waapParams = m_transaction->getSiteConfig()->get_WaapParametersPolicy();
if (waapParams != nullptr && waapParams->getParamVal("filtersVerbose", "false") == "true") {
m_transaction->getAssetState()->filterVerbose(param_name, res.filtered_keywords);
m_transaction->getAssetState()->filterKeywords(param_name, keywordsSet, res.filtered_keywords);
if (m_transaction->getSiteConfig() != nullptr)
{
auto waapParams = m_transaction->getSiteConfig()->get_WaapParametersPolicy();
if (waapParams != nullptr && waapParams->getParamVal("filtersVerbose", "false") == "true") {
m_transaction->getAssetState()->filterVerbose(param_name, res.filtered_keywords);
}
}
m_transaction->getAssetState()->filterKeywordsByParameters(res.param_name, keywordsSet);
dbgTrace(D_WAAP_SCANNER) << "post filtering indicators count: " << keywordsSet.size();
}
m_transaction->getAssetState()->filterKeywordsByParameters(res.param_name, keywordsSet);
// The keywords are only removed in production, they are still used while building scores
if (!m_transaction->get_ignoreScore()) {
m_transaction->getAssetState()->removeKeywords(keywordsSet);
@@ -148,9 +151,16 @@ bool Waap::Scanner::suspiciousHit(Waf2ScanResult& res, DeepParser &dp,
// Select scores pool by location
std::string poolName = Waap::Scores::getScorePoolNameByLocation(location);
Waf2ScanResult nonFilterRes = res;
res.scoreNoFilter = getScoreData(nonFilterRes, poolName, false);
double score = getScoreData(res, poolName);
dbgTrace(D_WAAP_SCANNER) << "score: " << score;
// call shouldIgnoreOverride post score calculation and filtering to evaluate ignore override effectivness
res.score = score;
m_transaction->shouldIgnoreOverride(res);
dbgTrace(D_WAAP_SCANNER) << "score: " << score << " should ignore: " << ignoreOverride;
// Add record about scores to the notes[] log (also reported in logs)
if (score > 1.0f) {
DetectionEvent(location, res.keyword_matches).notify();
@@ -166,6 +176,7 @@ bool Waap::Scanner::suspiciousHit(Waf2ScanResult& res, DeepParser &dp,
if (isKeyCspReport(key, res, dp) || ignoreOverride) {
dbgTrace(D_WAAP_SCANNER) << "Ignoring parameter key/value " << res.param_name <<
" due to ignore action in override";
res.score = 0;
m_bIgnoreOverride = true;
return false;
}

View File

@@ -43,7 +43,7 @@ namespace Waap {
static const std::string xmlEntityAttributeId;
private:
double getScoreData(Waf2ScanResult& res, const std::string &poolName);
double getScoreData(Waf2ScanResult& res, const std::string &poolName, bool applyLearning = true);
bool shouldIgnoreOverride(const Waf2ScanResult &res);
bool isKeyCspReport(const std::string &key, Waf2ScanResult &res, DeepParser &dp);

View File

@@ -329,6 +329,7 @@ Waf2Transaction::Waf2Transaction() :
is_schema_validation(false),
m_waf2TransactionFlags()
{
m_overrideOriginalMaxScore[OVERRIDE_ACCEPT] = 0;
I_TimeGet *timeGet = Singleton::Consume<I_TimeGet>::by<Waf2Transaction>();
m_entry_time = chrono::duration_cast<chrono::milliseconds>(timeGet->getMonotonicTime());
}
@@ -1516,6 +1517,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
@@ -1728,6 +1730,11 @@ void Waf2Transaction::appendCommonLogFields(LogGen& waapLog,
std::copy(m_effectiveOverrideIds.begin(), m_effectiveOverrideIds.end(), vEffectiveOverrideIds.begin());
waapLog.addToOrigin(LogField("effectiveExceptionIdList", vEffectiveOverrideIds));
}
if (!m_exceptionLearned.empty()) {
std::vector<std::string> vLearningAffected(m_exceptionLearned.size());
std::copy(m_exceptionLearned.begin(), m_exceptionLearned.end(), vLearningAffected.begin());
waapLog.addToOrigin(LogField("redundantExceptionIdList", vLearningAffected));
}
}
}
@@ -1808,12 +1815,6 @@ Waf2Transaction::sendLog()
return;
}
dbgTrace(D_WAAP) << "force exception: " << m_overrideState.bForceException <<
" force block: " << m_overrideState.bForceBlock <<
" matched overrides count: " << m_matchedOverrideIds.size() <<
" effective overrides count: " << m_effectiveOverrideIds.size();
bool shouldBlock = false;
if (m_overrideState.bForceBlock) {
// If override forces "reject" decision, mention it in the "override" log field.
@@ -2090,7 +2091,30 @@ Waf2Transaction::decideAutonomousSecurity(
transactionResult.threatLevel = threat;
}
dbgTrace(D_WAAP_OVERRIDE) << "override ids count: " << m_matchedOverrideIds.size();
// Apply overrides
for (auto it = m_overridePostFilterMaxScore.begin(); it != m_overridePostFilterMaxScore.end(); it++) {
const string id = it->first;
if (m_overrideState.forceBlockIds.find(id) != m_overrideState.forceBlockIds.end()) {
// blocked effectivness is calculates later from the force block exception ids list
continue;
}
ThreatLevel threat = Waap::Conversions::convertFinalScoreToThreatLevel(it->second);
bool shouldBlock = Waap::Conversions::shouldDoWafBlocking(m_siteConfig, threat);
dbgTrace(D_WAAP_OVERRIDE) << "checking effectivness of override: " << id << ", should have blocked: " << shouldBlock
<< ", scores: " << m_overridePostFilterMaxScore[id] << ", " << m_overrideOriginalMaxScore[id];
if (shouldBlock) {
m_effectiveOverrideIds.insert(id);
} else {
ThreatLevel threatNoFilter = Waap::Conversions::convertFinalScoreToThreatLevel(
m_overrideOriginalMaxScore[id]
);
if (Waap::Conversions::shouldDoWafBlocking(m_siteConfig, threatNoFilter)) {
m_exceptionLearned.insert(id);
}
}
}
if (m_overrideState.bForceBlock) {
dbgTrace(D_WAAP) << "decideAutonomousSecurity(): decision was " << decision->shouldBlock() <<
" and override forces REJECT ...";
@@ -2104,25 +2128,25 @@ Waf2Transaction::decideAutonomousSecurity(
}
}
else if (m_overrideState.bForceException) {
dbgTrace(D_WAAP) << "decideAutonomousSecurity(): decision was " << decision->shouldBlock() <<
dbgTrace(D_WAAP) << "de cideAutonomousSecurity(): decision was " << decision->shouldBlock() <<
" and override forces ALLOW ...";
if (m_scanResult) {
// on accept exception the decision is not set and needs to be calculated to determine effectivness
ThreatLevel threat = Waap::Conversions::convertFinalScoreToThreatLevel(m_scanResult->score);
bool shouldBlock = Waap::Conversions::shouldDoWafBlocking(&sitePolicy, threat);
if (shouldBlock) {
m_effectiveOverrideIds.insert(
m_overrideState.forceExceptionIds.begin(), m_overrideState.forceExceptionIds.end()
);
}
}
decision->setBlock(false);
if (!m_overrideState.bIgnoreLog)
{
decision->setOverridesLog(true);
}
} else if (!m_matchedOverrideIds.empty()) {
if (!m_overrideState.bIgnoreLog)
{
decision->setOverridesLog(true);
}
}
dbgTrace(D_WAAP_OVERRIDE) << "force exception: " << m_overrideState.bForceException <<
" force block: " << m_overrideState.bForceBlock <<
" matched overrides count: " << m_matchedOverrideIds.size() <<
" effective overrides count: " << m_effectiveOverrideIds.size() <<
" learned overrides count: " << m_exceptionLearned.size();
bool log_all = false;
@@ -2261,7 +2285,7 @@ bool
Waf2Transaction::shouldIgnoreOverride(const Waf2ScanResult &res) {
auto exceptions = getConfiguration<ParameterException>("rulebase", "exception");
if (!exceptions.ok()) {
dbgTrace(D_WAAP_OVERRIDE) << "matching exceptions error:" << exceptions.getErr();
dbgTrace(D_WAAP_OVERRIDE) << "matching exceptions error: " << exceptions.getErr();
return false;
}
dbgTrace(D_WAAP_OVERRIDE) << "matching exceptions";
@@ -2304,6 +2328,24 @@ Waf2Transaction::shouldIgnoreOverride(const Waf2ScanResult &res) {
auto behaviors = exceptions.unpack().getBehavior(exceptions_dict,
getAssetState()->m_filtersMngr->getMatchedOverrideKeywords());
for (const auto &behavior : behaviors) {
if (!res.filtered_keywords.empty() || res.score > 0) {
dbgTrace(D_WAAP_OVERRIDE) << "matched exceptions for " << res.param_name << " with filtered indicators";
std::string overrideId = behavior.getId();
if (m_overrideOriginalMaxScore.find(overrideId) == m_overrideOriginalMaxScore.end()){
m_overrideOriginalMaxScore[overrideId] = res.scoreNoFilter;
m_overridePostFilterMaxScore[overrideId] = res.score;
} else {
if (res.scoreNoFilter > m_overrideOriginalMaxScore[overrideId]) {
m_overrideOriginalMaxScore[overrideId] = res.scoreNoFilter;
}
if (res.score > m_overridePostFilterMaxScore[overrideId]) {
m_overridePostFilterMaxScore[overrideId] = res.score;
}
}
if (res.scoreNoFilter > m_overrideOriginalMaxScore[OVERRIDE_ACCEPT]) {
m_overrideOriginalMaxScore[OVERRIDE_ACCEPT] = res.scoreNoFilter;
}
}
if (behavior == action_ignore)
{
dbgTrace(D_WAAP_OVERRIDE) << "matched exceptions for " << res.param_name << " should ignore.";
@@ -2311,12 +2353,6 @@ Waf2Transaction::shouldIgnoreOverride(const Waf2ScanResult &res) {
if (!overrideId.empty()) {
m_matchedOverrideIds.insert(overrideId);
}
if (!res.keyword_matches.empty() || res.unescaped_line == Waap::Scanner::xmlEntityAttributeId)
{
if (!overrideId.empty()) {
m_effectiveOverrideIds.insert(overrideId);
}
}
return true;
}
}

View File

@@ -293,6 +293,9 @@ private:
// Matched override IDs
std::set<std::string> m_matchedOverrideIds;
std::set<std::string> m_effectiveOverrideIds;
std::set<std::string> m_exceptionLearned;
std::map<std::string, double> m_overrideOriginalMaxScore;
std::map<std::string, double> m_overridePostFilterMaxScore;
//csrf state
Waap::CSRF::State m_csrfState;

View File

@@ -459,9 +459,15 @@ Waf2Transaction::getUserLimitVerdict()
}
else if (mode == AttackMitigationMode::PREVENT) {
decision->setLog(true);
decision->setBlock(true);
dbgInfo(D_WAAP_ULIMITS) << msg << "BLOCK" << reason;
verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP;
if (!m_overrideState.bForceException) {
decision->setBlock(true);
dbgInfo(D_WAAP_ULIMITS) << msg << "BLOCK" << reason;
verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP;
} else {
decision->setBlock(true);
dbgInfo(D_WAAP_ULIMITS) << msg << "Override Accept" << reason;
verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT;
}
}
return verdict;
@@ -567,12 +573,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

@@ -733,6 +733,12 @@ inline void replaceAll(std::string& str, const std::string& from, const std::str
start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
}
}
inline std::string replaceAllCopy(std::string str, const std::string& from, const std::string& to) {
replaceAll(str, from, to);
return str;
}
inline void alignBase64Chunk (std::string &chunk)
{
size_t len = chunk.length() % 4;

Some files were not shown because too many files have changed in this diff Show More