diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index c48e065..ee7bf7d 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -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) diff --git a/components/health_check_manager/health_check_manager_ut/CMakeLists.txt b/components/health_check_manager/health_check_manager_ut/CMakeLists.txt deleted file mode 100755 index 99d8148..0000000 --- a/components/health_check_manager/health_check_manager_ut/CMakeLists.txt +++ /dev/null @@ -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" -) diff --git a/components/include/i_details_resolver.h b/components/include/i_details_resolver.h index b32a806..ecea297 100644 --- a/components/include/i_details_resolver.h +++ b/components/include/i_details_resolver.h @@ -31,7 +31,7 @@ public: virtual bool isReverseProxy() = 0; virtual bool isCloudStorageEnabled() = 0; virtual Maybe> parseNginxMetadata() = 0; - virtual Maybe> readCloudMetadata() = 0; + virtual Maybe> readCloudMetadata() = 0; virtual std::map getResolvedDetails() = 0; #if defined(gaia) || defined(smb) virtual bool compareCheckpointVersion(int cp_version, std::function compare_operator) const = 0; diff --git a/components/include/i_service_controller.h b/components/include/i_service_controller.h index d3d4f42..5deca00 100755 --- a/components/include/i_service_controller.h +++ b/components/include/i_service_controller.h @@ -64,7 +64,7 @@ public: const std::string &service_id ) = 0; - virtual std::map getServiceToPortMap() = 0; + virtual std::map> getServiceToPortMap() = 0; protected: virtual ~I_ServiceController() {} diff --git a/components/include/report_messaging.h b/components/include/report_messaging.h index 43f2f09..db618ce 100755 --- a/components/include/report_messaging.h +++ b/components/include/report_messaging.h @@ -36,7 +36,6 @@ public: title, audience_team, obj, - false, MessageCategory::GENERIC, std::forward(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)... - ) - { - } - - template - 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)... ) @@ -99,7 +77,6 @@ public: severity, priority, obj, - false, MessageCategory::GENERIC, std::forward(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)... ), - 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 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; }; diff --git a/components/report_messaging/report_messaging.cc b/components/report_messaging/report_messaging.cc index 290a1c2..077d3e7 100755 --- a/components/report_messaging/report_messaging.cc +++ b/components/report_messaging/report_messaging.cc @@ -24,6 +24,7 @@ static const string url = "/api/v1/agents/events"; ReportMessaging::~ReportMessaging() { if (!Singleton::exists()) 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 +ReportMessaging::sendReportSynchronously() +{ + is_async_message = false; + + LogRestWithReply log_rest(report); + + auto messaging = Singleton::Consume::by(); + return messaging->sendSyncMessage(HTTPMethod::POST, url, log_rest, message_type_tag); +} + void ReportMessaging::setForceBuffering(bool _force_buffering) { diff --git a/components/report_messaging/report_messaging_ut/report_messaging_ut.cc b/components/report_messaging/report_messaging_ut/report_messaging_ut.cc index 85a2743..0ecb549 100644 --- a/components/report_messaging/report_messaging_ut/report_messaging_ut.cc +++ b/components/report_messaging/report_messaging_ut/report_messaging_ut.cc @@ -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); } diff --git a/components/security_apps/http_geo_filter/http_geo_filter.cc b/components/security_apps/http_geo_filter/http_geo_filter.cc index 3e343bc..a619b0e 100644 --- a/components/security_apps/http_geo_filter/http_geo_filter.cc +++ b/components/security_apps/http_geo_filter/http_geo_filter.cc @@ -361,19 +361,10 @@ private: << ", source ip address: " << source; - unordered_map> 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> 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::by(); - auto source_ip = env->get(HttpTransactionData::client_ip_ctx); - if (source_ip.ok()) log << LogField("sourceIP", source_ip.unpack()); + auto source_ip = env->get(HttpTransactionData::client_ip_ctx); + if (source_ip.ok()) log << LogField("sourceIP", convertIpAddrToString(source_ip.unpack())); + + auto source_identifier = env->get(HttpTransactionData::source_identifier); + if (source_identifier.ok()) log << LogField("httpSourceId", source_identifier.unpack()); auto source_port = env->get(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(HttpTransactionData::xff_vals_ctx); + auto xff = env->get(HttpTransactionData::xff_vals_ctx); if (xff.ok()) log << LogField("proxyIP", xff.unpack()); log diff --git a/components/security_apps/orchestration/CMakeLists.txt b/components/security_apps/orchestration/CMakeLists.txt index 4c500e8..5c067b8 100755 --- a/components/security_apps/orchestration/CMakeLists.txt +++ b/components/security_apps/orchestration/CMakeLists.txt @@ -12,6 +12,8 @@ add_subdirectory(manifest_controller) add_subdirectory(update_communication) add_subdirectory(details_resolver) add_subdirectory(health_check) +add_subdirectory(health_check_manager) +add_subdirectory(updates_process_reporter) add_subdirectory(env_details) #add_subdirectory(orchestration_ut) diff --git a/components/security_apps/orchestration/details_resolver/details_resolver.cc b/components/security_apps/orchestration/details_resolver/details_resolver.cc index 4c90d49..1fc4360 100644 --- a/components/security_apps/orchestration/details_resolver/details_resolver.cc +++ b/components/security_apps/orchestration/details_resolver/details_resolver.cc @@ -45,7 +45,7 @@ public: bool isVersionAboveR8110() override; bool isReverseProxy() override; bool isCloudStorageEnabled() override; - Maybe> readCloudMetadata() override; + Maybe> readCloudMetadata() override; Maybe> parseNginxMetadata() override; #if defined(gaia) || defined(smb) bool compareCheckpointVersion(int cp_version, std::function compare_operator) const override; @@ -300,19 +300,26 @@ DetailsResolver::Impl::parseNginxMetadata() return make_tuple(config_opt, cc_opt, nginx_version); } -Maybe> +Maybe> DetailsResolver::Impl::readCloudMetadata() { - auto env_read_cloud_metadata = []() -> Maybe> { + auto env_read_cloud_metadata = []() -> Maybe> { string account_id = getenv("CLOUD_ACCOUNT_ID") ? getenv("CLOUD_ACCOUNT_ID") : ""; string vpc_id = getenv("CLOUD_VPC_ID") ? getenv("CLOUD_VPC_ID") : ""; string instance_id = getenv("CLOUD_INSTANCE_ID") ? getenv("CLOUD_INSTANCE_ID") : ""; + string instance_local_ip = getenv("CLOUD_INSTANCE_LOCAL_IP") ? getenv("CLOUD_INSTANCE_LOCAL_IP") : ""; + string region = getenv("CLOUD_REGION") ? getenv("CLOUD_REGION") : ""; - if (account_id.empty() || vpc_id.empty() || instance_id.empty()) { + if ( + account_id.empty() || + vpc_id.empty() || + instance_id.empty() || + instance_local_ip.empty() || + region.empty()) { return genError("Could not read cloud metadata"); } - return make_tuple(account_id, vpc_id, instance_id); + return make_tuple(account_id, vpc_id, instance_id, instance_local_ip, region); }; auto cloud_metadata = env_read_cloud_metadata(); @@ -347,9 +354,11 @@ DetailsResolver::Impl::readCloudMetadata() << "Successfully fetched cloud metadata: " << ::get<0>(cloud_metadata.unpack()) << ", " << ::get<1>(cloud_metadata.unpack()) << ", " - << ::get<2>(cloud_metadata.unpack()); + << ::get<2>(cloud_metadata.unpack()) << ", " + << ::get<3>(cloud_metadata.unpack()) << ", " + << ::get<4>(cloud_metadata.unpack()); - return cloud_metadata.unpack(); + return cloud_metadata; } DetailsResolver::DetailsResolver() : Component("DetailsResolver"), pimpl(make_unique()) {} diff --git a/components/security_apps/orchestration/details_resolver/details_resolver_handlers/checkpoint_product_handlers.h b/components/security_apps/orchestration/details_resolver/details_resolver_handlers/checkpoint_product_handlers.h index 339ed8f..3801ae1 100755 --- a/components/security_apps/orchestration/details_resolver/details_resolver_handlers/checkpoint_product_handlers.h +++ b/components/security_apps/orchestration/details_resolver/details_resolver_handlers/checkpoint_product_handlers.h @@ -58,27 +58,20 @@ checkSAMLPortal(const string &command_output) Maybe 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 -checkAgentIntelligence(const string &command_output) -{ - if (command_output.find("is registered") != string::npos) { - return string("true"); - } - - return genError("Current host does not have agent intelligence installed"); + return genError("Current host does not have PEP control scaled_sharing enabled"); } Maybe 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 diff --git a/components/security_apps/orchestration/details_resolver/details_resolver_handlers/details_resolver_impl.h b/components/security_apps/orchestration/details_resolver/details_resolver_handlers/details_resolver_impl.h index 7615460..51b1118 100755 --- a/components/security_apps/orchestration/details_resolver/details_resolver_handlers/details_resolver_impl.h +++ b/components/security_apps/orchestration/details_resolver/details_resolver_handlers/details_resolver_impl.h @@ -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", - "/watchdog/cp-nano-watchdog " - "--status --service /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 " diff --git a/components/security_apps/orchestration/health_check/health_check_ut/CMakeLists.txt b/components/security_apps/orchestration/health_check/health_check_ut/CMakeLists.txt index 8553708..e7ef859 100755 --- a/components/security_apps/orchestration/health_check/health_check_ut/CMakeLists.txt +++ b/components/security_apps/orchestration/health_check/health_check_ut/CMakeLists.txt @@ -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" ) diff --git a/components/health_check_manager/CMakeLists.txt b/components/security_apps/orchestration/health_check_manager/CMakeLists.txt similarity index 57% rename from components/health_check_manager/CMakeLists.txt rename to components/security_apps/orchestration/health_check_manager/CMakeLists.txt index fd4127e..cb6c1e0 100755 --- a/components/health_check_manager/CMakeLists.txt +++ b/components/security_apps/orchestration/health_check_manager/CMakeLists.txt @@ -1,3 +1 @@ add_library(health_check_manager health_check_manager.cc) - -add_subdirectory(health_check_manager_ut) diff --git a/components/health_check_manager/health_check_manager.cc b/components/security_apps/orchestration/health_check_manager/health_check_manager.cc old mode 100755 new mode 100644 similarity index 54% rename from components/health_check_manager/health_check_manager.cc rename to components/security_apps/orchestration/health_check_manager/health_check_manager.cc index ea73d5d..7439acd --- a/components/health_check_manager/health_check_manager.cc +++ b/components/security_apps/orchestration/health_check_manager/health_check_manager.cc @@ -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 &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 &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::From + Singleton::Provide::From, + public Listener { public: void @@ -132,6 +137,7 @@ public: auto rest = Singleton::Consume::by(); rest->addRestCall(RestAction::SHOW, "health-check-on-demand"); + registerListener(); int interval_in_seconds = getProfileAgentSettingWithDefault(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::by(); - return messaging->sendSyncMessageWithoutResponse( + HealthCheckPatch patch_to_send(general_health_aggregated_status, health_check_reply); + extended_status.clear(); + field_types_status.clear(); + return Singleton::Consume::by()->sendSyncMessageWithoutResponse( HTTPMethod::PATCH, "/agents", patch_to_send, @@ -178,59 +238,11 @@ private: ); } - void - getRegisteredComponentsHealthStatus() - { - vector 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 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 extended_status; + map field_types_status; }; HealthCheckManager::HealthCheckManager() : Component("HealthCheckManager"), pimpl(make_unique()) {} diff --git a/components/health_check_manager/health_check_manager_ut/health_check_manager_ut.cc b/components/security_apps/orchestration/health_check_manager/health_check_manager_ut/health_check_manager_ut.cc old mode 100755 new mode 100644 similarity index 74% rename from components/health_check_manager/health_check_manager_ut/health_check_manager_ut.cc rename to components/security_apps/orchestration/health_check_manager/health_check_manager_ut/health_check_manager_ut.cc index 8a69986..a4e59c3 --- a/components/health_check_manager/health_check_manager_ut/health_check_manager_ut.cc +++ b/components/security_apps/orchestration/health_check_manager/health_check_manager_ut/health_check_manager_ut.cc @@ -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 -{ -public: - void upon(const HealthCheckStatusEvent &) override {} - - HealthCheckStatusReply - respond(const HealthCheckStatusEvent &) override - { - map 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 mock_ml; StrictMock mock_rest; StrictMock 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 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::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" "}"; diff --git a/components/security_apps/orchestration/include/mock/mock_details_resolver.h b/components/security_apps/orchestration/include/mock/mock_details_resolver.h index cf0d69a..3c4a153 100644 --- a/components/security_apps/orchestration/include/mock/mock_details_resolver.h +++ b/components/security_apps/orchestration/include/mock/mock_details_resolver.h @@ -26,6 +26,13 @@ operator<<(std::ostream &os, const Maybe> &) +{ + return os; +} + class MockDetailsResolver : public Singleton::Provide::From> @@ -42,7 +49,8 @@ public: MOCK_METHOD0(getResolvedDetails, std::map()); MOCK_METHOD0(isVersionAboveR8110, bool()); MOCK_METHOD0(parseNginxMetadata, Maybe>()); - MOCK_METHOD0(readCloudMetadata, Maybe>()); + MOCK_METHOD0( + readCloudMetadata, Maybe>()); }; #endif // __MOCK_DETAILS_RESOLVER_H__ diff --git a/components/security_apps/orchestration/include/mock/mock_service_controller.h b/components/security_apps/orchestration/include/mock/mock_service_controller.h index e32fea9..0495075 100755 --- a/components/security_apps/orchestration/include/mock/mock_service_controller.h +++ b/components/security_apps/orchestration/include/mock/mock_service_controller.h @@ -64,7 +64,7 @@ public: ) ); - typedef std::map ServicePortMap; + typedef std::map> ServicePortMap; MOCK_METHOD0(getServiceToPortMap, ServicePortMap()); MOCK_METHOD3(updateReconfStatus, void(int id, const std::string &service_name, ReconfStatus status)); MOCK_METHOD4( diff --git a/components/security_apps/orchestration/include/updates_process_event.h b/components/security_apps/orchestration/include/updates_process_event.h new file mode 100644 index 0000000..12eab13 --- /dev/null +++ b/components/security_apps/orchestration/include/updates_process_event.h @@ -0,0 +1,130 @@ +// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __UPDATES_PROCESS_EVENT_H__ +#define __UPDATES_PROCESS_EVENT_H__ + +#include "event.h" +#include "singleton.h" +#include "config.h" +#include "debug.h" +#include "i_orchestration_status.h" +#include "health_check_status/health_check_status.h" +#include "customized_cereal_map.h" + +USE_DEBUG_FLAG(D_UPDATES_PROCESS_REPORTER); + +enum class UpdatesFailureReason { + CHECK_UPDATE, + REGISTRATION, + ORCHESTRATION_SELF_UPDATE, + GET_UPDATE_REQUEST, + DOWNLOAD_FILE, + HANDLE_FILE, + INSTALLATION_QUEUE, + INSTALL_PACKAGE, + CHECKSUM_UNMATCHED, + POLICY_CONFIGURATION, + POLICY_FOG_CONFIGURATION, + NONE + +}; + +enum class UpdatesConfigType { MANIFEST, POLICY, SETTINGS, DATA, GENERAL }; +enum class UpdatesProcessResult { UNSET, SUCCESS, FAILED, DEGRADED }; + +static inline std::string +convertUpdatesFailureReasonToStr(UpdatesFailureReason reason) +{ + switch (reason) { + case UpdatesFailureReason::CHECK_UPDATE : return "CHECK_UPDATE"; + case UpdatesFailureReason::REGISTRATION : return "REGISTRATION"; + case UpdatesFailureReason::ORCHESTRATION_SELF_UPDATE : return "ORCHESTRATION_SELF_UPDATE"; + case UpdatesFailureReason::GET_UPDATE_REQUEST : return "GET_UPDATE_REQUEST"; + case UpdatesFailureReason::DOWNLOAD_FILE : return "DOWNLOAD_FILE"; + case UpdatesFailureReason::HANDLE_FILE : return "HANDLE_FILE"; + case UpdatesFailureReason::INSTALLATION_QUEUE : return "INSTALLATION_QUEUE"; + case UpdatesFailureReason::INSTALL_PACKAGE : return "INSTALL_PACKAGE"; + case UpdatesFailureReason::CHECKSUM_UNMATCHED : return "CHECKSUM_UNMATCHED"; + case UpdatesFailureReason::POLICY_CONFIGURATION : return "POLICY_CONFIGURATION"; + case UpdatesFailureReason::POLICY_FOG_CONFIGURATION : return "POLICY_FOG_CONFIGURATION"; + case UpdatesFailureReason::NONE : return "NONE"; + } + + dbgWarning(D_UPDATES_PROCESS_REPORTER) << "Trying to convert unknown updates failure reason to string."; + return ""; +} + +static inline std::string +convertUpdatesConfigTypeToStr(UpdatesConfigType type) +{ + switch (type) { + case UpdatesConfigType::MANIFEST : return "MANIFEST"; + case UpdatesConfigType::POLICY : return "POLICY"; + case UpdatesConfigType::SETTINGS : return "SETTINGS"; + case UpdatesConfigType::DATA : return "DATA"; + case UpdatesConfigType::GENERAL : return "GENERAL"; + } + + dbgWarning(D_UPDATES_PROCESS_REPORTER) << "Trying to convert unknown updates failure reason to string."; + return ""; +} + +static inline std::string +convertUpdateProcessResultToStr(UpdatesProcessResult result) +{ + switch (result) { + case UpdatesProcessResult::SUCCESS : return "SUCCESS"; + case UpdatesProcessResult::UNSET : return "UNSET"; + case UpdatesProcessResult::FAILED : return "FAILURE"; + case UpdatesProcessResult::DEGRADED : return "DEGRADED"; + } + + dbgWarning(D_UPDATES_PROCESS_REPORTER) << "Trying to convert unknown updates failure reason to string."; + return ""; +} + +class UpdatesProcessEvent : public Event +{ +public: + UpdatesProcessEvent() {} + UpdatesProcessEvent( + UpdatesProcessResult _result, + UpdatesConfigType _type, + UpdatesFailureReason _reason = UpdatesFailureReason::NONE, + const std::string &_detail = "", + const std::string &_description = ""); + + ~UpdatesProcessEvent() {} + + UpdatesProcessResult getResult() const { return result; } + UpdatesConfigType getType() const { return type; } + UpdatesFailureReason getReason() const { return reason; } + std::string getDetail() const { return detail; } + std::string getDescription() const { return description; } + + OrchestrationStatusFieldType getStatusFieldType() const; + OrchestrationStatusResult getOrchestrationStatusResult() const; + + std::string parseDescription() const; + +private: + UpdatesProcessResult result; + UpdatesConfigType type; + UpdatesFailureReason reason; + std::string detail; + std::string description; + +}; + +#endif // __UPDATES_PROCESS_EVENT_H__ diff --git a/components/security_apps/orchestration/include/updates_process_report.h b/components/security_apps/orchestration/include/updates_process_report.h new file mode 100644 index 0000000..f7d2f0f --- /dev/null +++ b/components/security_apps/orchestration/include/updates_process_report.h @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __UPDATES_PROCESS_REPORT_H__ +#define __UPDATES_PROCESS_REPORT_H__ + +#include +#include + +#include "singleton.h" +#include "i_time_get.h" +#include "updates_process_event.h" + +class UpdatesProcessReport : Singleton::Consume +{ +public: + UpdatesProcessReport( + UpdatesProcessResult result, + UpdatesConfigType type, + UpdatesFailureReason reason, + const std::string &description) + : + result(result), type(type), reason(reason), description(description) + { + time_stamp = Singleton::Consume::by()->getWalltimeStr(); + } + + std::string + toString() const + { + std::stringstream report; + report + << "[" + << time_stamp << "] - " + << convertUpdateProcessResultToStr(result) << " | " + << convertUpdatesConfigTypeToStr(type) << " | " + << convertUpdatesFailureReasonToStr(reason) << " | " + << description; + + return report.str(); + } + +private: + UpdatesProcessResult result; + UpdatesConfigType type; + UpdatesFailureReason reason; + std::string description; + std::string time_stamp; +}; + +#endif // __UPDATES_PROCESS_EVENT_H__ diff --git a/components/security_apps/orchestration/include/updates_process_reporter.h b/components/security_apps/orchestration/include/updates_process_reporter.h new file mode 100644 index 0000000..75567e4 --- /dev/null +++ b/components/security_apps/orchestration/include/updates_process_reporter.h @@ -0,0 +1,39 @@ +// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __UPDATES_PROCESS_REPORTER_H__ +#define __UPDATES_PROCESS_REPORTER_H__ + +#include + +#include "event.h" +#include "singleton.h" +#include "config.h" +#include "debug.h" +#include "i_orchestration_status.h" +#include "health_check_status/health_check_status.h" +#include "updates_process_event.h" +#include "updates_process_report.h" + +class UpdatesProcessReporter : public Listener +{ +public: + void upon(const UpdatesProcessEvent &event) override; + +private: + void sendReoprt(); + + static std::vector reports; +}; + +#endif // __UPDATES_PROCESS_REPORTER_H__ diff --git a/components/security_apps/orchestration/manifest_controller/manifest_controller.cc b/components/security_apps/orchestration/manifest_controller/manifest_controller.cc index a0662c8..dfc7870 100755 --- a/components/security_apps/orchestration/manifest_controller/manifest_controller.cc +++ b/components/security_apps/orchestration/manifest_controller/manifest_controller.cc @@ -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> 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 &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; } diff --git a/components/security_apps/orchestration/manifest_controller/manifest_controller_ut/manifest_controller_ut.cc b/components/security_apps/orchestration/manifest_controller/manifest_controller_ut/manifest_controller_ut.cc index 1cb2f88..9441867 100755 --- a/components/security_apps/orchestration/manifest_controller/manifest_controller_ut/manifest_controller_ut.cc +++ b/components/security_apps/orchestration/manifest_controller/manifest_controller_ut/manifest_controller_ut.cc @@ -281,13 +281,7 @@ TEST_F(ManifestControllerTest, badChecksum) EXPECT_CALL(mock_orchestration_tools, doesFileExist("/etc/cp/packages/my/my")).WillOnce(Return(false)); string hostname = "hostname"; - string empty_err; - EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(empty_err)); EXPECT_CALL(mock_details_resolver, getHostname()).WillOnce(Return( Maybe(hostname))); - EXPECT_CALL( - mock_status, - setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::FAILED, _) - ); EXPECT_FALSE(i_manifest_controller->updateManifest(file_name)); } @@ -710,10 +704,6 @@ TEST_F(ManifestControllerTest, selfUpdateWithOldCopyWithError) string hostname = "hostname"; string empty_err; EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(empty_err)); - EXPECT_CALL( - mock_status, - setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::FAILED, _) - ); load(manifest, new_services); EXPECT_CALL(mock_orchestration_tools, @@ -932,10 +922,6 @@ TEST_F(ManifestControllerTest, badInstall) string empty_err; EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(empty_err)); EXPECT_CALL(mock_details_resolver, getHostname()).WillOnce(Return( Maybe(hostname))); - EXPECT_CALL( - mock_status, - setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::FAILED, _) - ); string corrupted_packages_manifest = "{" @@ -1008,12 +994,6 @@ TEST_F(ManifestControllerTest, failToDownloadWithselfUpdate) doesFileExist("/etc/cp/packages/orchestration/orchestration") ).WillOnce(Return(false)); EXPECT_CALL(mock_details_resolver, getHostname()).WillOnce(Return(string("hostname"))); - EXPECT_CALL( - mock_status, - setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::FAILED, _) - ); - string not_error; - EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(not_error)); EXPECT_FALSE(i_manifest_controller->updateManifest(file_name)); } @@ -1404,12 +1384,6 @@ TEST_F(ManifestControllerTest, failureOnDownloadSharedObject) ).WillOnce(Return(false)); EXPECT_CALL(mock_details_resolver, getHostname()).WillOnce(Return(string("hostname"))); EXPECT_CALL(mock_orchestration_tools, removeFile("/tmp/temp_file1")).WillOnce(Return(true)); - EXPECT_CALL( - mock_status, - setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::FAILED, _) - ); - string not_error; - EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(not_error)); EXPECT_FALSE(i_manifest_controller->updateManifest(file_name)); } @@ -2538,12 +2512,6 @@ TEST_F(ManifestDownloadTest, download_relative_path) doesFileExist("/etc/cp/packages/orchestration/orchestration") ).WillOnce(Return(false)); EXPECT_CALL(mock_details_resolver, getHostname()).WillOnce(Return(string("hostname"))); - EXPECT_CALL( - mock_status, - setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::FAILED, _) - ); - string not_error; - EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(not_error)); EXPECT_FALSE(i_manifest_controller->updateManifest(manifest_file.fname)); } @@ -2589,8 +2557,6 @@ TEST_F(ManifestDownloadTest, download_relative_path_no_fog_domain) mock_orchestration_tools, doesFileExist("/etc/cp/packages/orchestration/orchestration") ).WillOnce(Return(false)); - string not_error; - EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(not_error)); checkIfFileExistsCall(new_packages.at("orchestration")); @@ -2604,10 +2570,6 @@ TEST_F(ManifestDownloadTest, download_relative_path_no_fog_domain) ) ).WillOnce(Return(downloaded_package)); EXPECT_CALL(mock_details_resolver, getHostname()).WillOnce(Return(string("hostname"))); - EXPECT_CALL( - mock_status, - setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::FAILED, _) - ); EXPECT_FALSE(i_manifest_controller->updateManifest(manifest_file.fname)); } diff --git a/components/security_apps/orchestration/manifest_controller/manifest_handler.cc b/components/security_apps/orchestration/manifest_controller/manifest_handler.cc index c2cbd7e..e196637 100755 --- a/components/security_apps/orchestration/manifest_controller/manifest_handler.cc +++ b/components/security_apps/orchestration/manifest_controller/manifest_handler.cc @@ -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 &new_packages_to_do " software update failed. Agent is running previous software. Contact Check Point support."; } - auto orchestration_status = Singleton::Consume::by(); - 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::by(); 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; } diff --git a/components/security_apps/orchestration/modules/modules_ut/orchestration_status_ut.cc b/components/security_apps/orchestration/modules/modules_ut/orchestration_status_ut.cc index 6c902ed..08b870c 100755 --- a/components/security_apps/orchestration/modules/modules_ut/orchestration_status_ut.cc +++ b/components/security_apps/orchestration/modules/modules_ut/orchestration_status_ut.cc @@ -13,6 +13,7 @@ #include "mock/mock_agent_details.h" #include "mock/mock_mainloop.h" #include "mock/mock_rest_api.h" +#include "updates_process_event.h" using namespace testing; using namespace std; @@ -200,6 +201,19 @@ TEST_F(OrchestrationStatusTest, checkUpdateStatus) auto result = orchestrationStatusFileToString(); EXPECT_EQ(buildOrchestrationStatusJSON("attempt time", "Succeeded ", "current time"), result); } +TEST_F(OrchestrationStatusTest, checkUpdateStatusByRaiseEvent) +{ + init(); + EXPECT_CALL(time, getLocalTimeStr()) + .WillOnce(Return(string("attempt time"))) + .WillOnce(Return(string("current time"))); + + i_orchestration_status->setLastUpdateAttempt(); + + UpdatesProcessEvent(UpdatesProcessResult::SUCCESS, UpdatesConfigType::GENERAL).notify(); + auto result = orchestrationStatusFileToString(); + EXPECT_EQ(buildOrchestrationStatusJSON("attempt time", "Succeeded ", "current time"), result); +} TEST_F(OrchestrationStatusTest, recoveryFields) { @@ -482,3 +496,69 @@ TEST_F(OrchestrationStatusTest, setAllFields) EXPECT_EQ(i_orchestration_status->getServiceSettings(), service_map_a); EXPECT_EQ(i_orchestration_status->getRegistrationDetails(), agent_details); } + +TEST_F(OrchestrationStatusTest, checkErrorByRaiseEvent) +{ + init(); + string fog_address = "http://fog.address"; + string registar_error = "Fail to registar"; + string manifest_error = "Fail to achieve manifest"; + string last_update_error = "Fail to update"; + + EXPECT_CALL(time, getLocalTimeStr()).Times(3).WillRepeatedly(Return(string("Time"))); + + UpdatesProcessEvent(UpdatesProcessResult::SUCCESS, UpdatesConfigType::GENERAL).notify(); + i_orchestration_status->setIsConfigurationUpdated( + EnumArray(true, true, true) + ); + UpdatesProcessEvent( + UpdatesProcessResult::FAILED, + UpdatesConfigType::GENERAL, + UpdatesFailureReason::NONE, + "", + last_update_error + ).notify(); + i_orchestration_status->setIsConfigurationUpdated( + EnumArray(false, false, false) + ); + + i_orchestration_status->setUpgradeMode("Online upgrades"); + i_orchestration_status->setFogAddress(fog_address); + + i_orchestration_status->setUpgradeMode("Online upgrades"); + i_orchestration_status->setFogAddress(fog_address); + + UpdatesProcessEvent( + UpdatesProcessResult::FAILED, + UpdatesConfigType::GENERAL, + UpdatesFailureReason::REGISTRATION, + "", + registar_error + ).notify(); + UpdatesProcessEvent( + UpdatesProcessResult::FAILED, + UpdatesConfigType::MANIFEST, + UpdatesFailureReason::NONE, + "", + manifest_error + ).notify(); + EXPECT_EQ(i_orchestration_status->getManifestError(), manifest_error); + + auto result = orchestrationStatusFileToString(); + EXPECT_EQ( + buildOrchestrationStatusJSON( + "None", + "Failed. Reason: " + last_update_error, + "Time", + "Time", + "", + "Time", + "Time", + "Online upgrades", + fog_address, + "Failed. Reason: Registration failed. Error: " + registar_error, + "Failed. Reason: " + manifest_error + ), + result + ); +} diff --git a/components/security_apps/orchestration/modules/orchestration_status.cc b/components/security_apps/orchestration/modules/orchestration_status.cc index 112f868..331a10b 100755 --- a/components/security_apps/orchestration/modules/orchestration_status.cc +++ b/components/security_apps/orchestration/modules/orchestration_status.cc @@ -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 service_settings; }; -class OrchestrationStatus::Impl : Singleton::Provide::From +class OrchestrationStatus::Impl + : + Singleton::Provide::From, + public Listener { public: void @@ -462,6 +467,13 @@ public: }, "Write Orchestration status file" ); + registerListener(); + } + + void + upon(const UpdatesProcessEvent &event) override + { + setFieldStatus(event.getStatusFieldType(), event.getOrchestrationStatusResult(), event.parseDescription()); } private: diff --git a/components/security_apps/orchestration/orchestration_comp.cc b/components/security_apps/orchestration/orchestration_comp.cc index eb9f357..4fccec2 100755 --- a/components/security_apps/orchestration/orchestration_comp.cc +++ b/components/security_apps/orchestration/orchestration_comp.cc @@ -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 -{ -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 extended_status; - map 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 new_policy_file = - Singleton::Consume::by()->downloadFile( + Maybe new_policy_file = Singleton::Consume::by()->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(); @@ -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 new_data_file = - Singleton::Consume::by()->downloadFileFromURL( - data_file.second.getDownloadPath(), - data_file.second.getChecksum(), - I_OrchestrationTools::SELECTED_CHECKSUM_TYPE, - "data_" + data_file.first - ); + Singleton::Consume::by()->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(); } @@ -751,8 +740,7 @@ private: dbgInfo(D_ORCHESTRATOR) << "There is a new settings file."; GetResourceFile resource_file(GetResourceFile::ResourceFileType::SETTINGS); - Maybe new_settings_file = - Singleton::Consume::by()->downloadFile( + Maybe new_settings_file = Singleton::Consume::by()->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(); } @@ -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( 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(); } @@ -1196,6 +1201,13 @@ private: dbgTrace(D_ORCHESTRATOR) << "The settings directory is " << settings_file_path; if (!i_orchestration_tools->copyFile(new_settings_file, settings_file_path)) { dbgWarning(D_ORCHESTRATOR) << "Failed to update the settings."; + UpdatesProcessEvent( + UpdatesProcessResult::FAILED, + UpdatesConfigType::SETTINGS, + UpdatesFailureReason::HANDLE_FILE, + settings_file_path, + "Failed to update the settings" + ).notify(); return genError("Failed to update the settings"); } @@ -1303,6 +1315,8 @@ private: report << make_pair("cloudAccountId", ::get<0>(cloud_metadata.unpack())); report << make_pair("cloudVpcId", ::get<1>(cloud_metadata.unpack())); report << make_pair("cloudInstanceId", ::get<2>(cloud_metadata.unpack())); + report << make_pair("cloudInstanceLocalIp", ::get<3>(cloud_metadata.unpack())); + report << make_pair("cloudRegion", ::get<4>(cloud_metadata.unpack())); } void @@ -1443,20 +1457,24 @@ private: << check_update_result.getErr() << ", new check will be every: " << sleep_interval << " seconds"; - - health_check_status_listener.setStatus( - HealthCheckStatus::UNHEALTHY, - OrchestrationStatusFieldType::LAST_UPDATE, + UpdatesProcessEvent( + UpdatesProcessResult::FAILED, + UpdatesConfigType::GENERAL, + UpdatesFailureReason::CHECK_UPDATE, + "", "Failed during check update. Error: " + check_update_result.getErr() - ); + ).notify(); return; } failure_count = 0; dbgDebug(D_ORCHESTRATOR) << "Check update process completed successfully"; - health_check_status_listener.setStatus( - HealthCheckStatus::HEALTHY, - OrchestrationStatusFieldType::LAST_UPDATE - ); + UpdatesProcessEvent( + UpdatesProcessResult::SUCCESS, + UpdatesConfigType::GENERAL, + UpdatesFailureReason::CHECK_UPDATE, + "", + "Check update procces succeeded!" + ).notify(); sleep_interval = policy.getSleepInterval(); if (!is_new_success) { dbgInfo(D_ORCHESTRATOR) @@ -1491,11 +1509,13 @@ private: sleep_interval = policy.getErrorSleepInterval(); Maybe 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( 30, "orchestration", @@ -1515,10 +1535,11 @@ private: Singleton::Consume::by()->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::by()->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; diff --git a/components/security_apps/orchestration/orchestration_tools/orchestration_tools.cc b/components/security_apps/orchestration/orchestration_tools/orchestration_tools.cc index 929abfe..4c88c5c 100755 --- a/components/security_apps/orchestration/orchestration_tools/orchestration_tools.cc +++ b/components/security_apps/orchestration/orchestration_tools/orchestration_tools.cc @@ -20,6 +20,7 @@ #include "cereal/types/set.hpp" #include "agent_core_utilities.h" #include "namespace_data.h" +#include "updates_process_event.h" #include #include @@ -469,6 +470,13 @@ OrchestrationTools::Impl::packagesToJsonFile(const map &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; diff --git a/components/security_apps/orchestration/orchestration_ut/orchestration_multitenant_ut.cc b/components/security_apps/orchestration/orchestration_ut/orchestration_multitenant_ut.cc index e85485b..f3bdd6a 100644 --- a/components/security_apps/orchestration/orchestration_ut/orchestration_multitenant_ut.cc +++ b/components/security_apps/orchestration/orchestration_ut/orchestration_multitenant_ut.cc @@ -144,7 +144,7 @@ public: map 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>(genError("No cloud metadata"))) + Return(Maybe>(genError("No cloud metadata"))) ); } @@ -284,7 +284,7 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource) EXPECT_CALL(mock_service_controller, getPolicyVersion()) .Times(3).WillRepeatedly(ReturnRef(first_policy_version)); - map empty_service_to_port_map; + map> empty_service_to_port_map; EXPECT_CALL(mock_service_controller, getServiceToPortMap()).WillRepeatedly(Return(empty_service_to_port_map)); diff --git a/components/security_apps/orchestration/orchestration_ut/orchestration_ut.cc b/components/security_apps/orchestration/orchestration_ut/orchestration_ut.cc index edc9c3e..a6d38cc 100755 --- a/components/security_apps/orchestration/orchestration_ut/orchestration_ut.cc +++ b/components/security_apps/orchestration/orchestration_ut/orchestration_ut.cc @@ -22,6 +22,7 @@ #include "agent_details.h" #include "customized_cereal_map.h" #include "health_check_status/health_check_status.h" +#include "updates_process_event.h" #include "declarative_policy_utils.h" using namespace testing; @@ -99,7 +100,7 @@ public: ) ); - map empty_service_to_port_map; + map> empty_service_to_port_map; EXPECT_CALL(mock_service_controller, getServiceToPortMap()).WillRepeatedly(Return(empty_service_to_port_map)); EXPECT_CALL(rest, mockRestCall(RestAction::SHOW, "orchestration-status", _)).WillOnce( @@ -171,7 +172,7 @@ public: map 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>(genError("No cloud metadata"))) + Return(Maybe>(genError("No cloud metadata"))) ); } @@ -358,6 +359,7 @@ private: TEST_F(OrchestrationTest, hybridModeRegisterLocalAgentRoutine) { EXPECT_CALL(rest, mockRestCall(_, _, _)).WillRepeatedly(Return(true)); + Singleton::Consume::from(config_comp)->loadConfiguration( vector{"--orchestration-mode=hybrid_mode"} ); @@ -376,7 +378,6 @@ TEST_F(OrchestrationTest, hybridModeRegisterLocalAgentRoutine) expectDetailsResolver(); EXPECT_CALL(mock_update_communication, getUpdate(_)); EXPECT_CALL(mock_status, setLastUpdateAttempt()); - EXPECT_CALL(mock_status, setFieldStatus(_, _, _)); EXPECT_CALL(mock_status, setIsConfigurationUpdated(_)); EXPECT_CALL(mock_ml, yield(A())) @@ -584,7 +585,6 @@ TEST_F(OrchestrationTest, check_sending_registration_data) expectDetailsResolver(); EXPECT_CALL(mock_update_communication, getUpdate(_)); EXPECT_CALL(mock_status, setLastUpdateAttempt()); - EXPECT_CALL(mock_status, setFieldStatus(_, _, _)); EXPECT_CALL(mock_status, setIsConfigurationUpdated(_)); EXPECT_CALL(mock_ml, yield(A())) @@ -761,10 +761,6 @@ TEST_F(OrchestrationTest, orchestrationPolicyUpdatRollback) ).WillOnce(Return(true)); EXPECT_CALL(mock_update_communication, setAddressExtenesion("/test")); EXPECT_CALL(mock_status, setLastUpdateAttempt()); - EXPECT_CALL( - mock_status, - setFieldStatus(OrchestrationStatusFieldType::LAST_UPDATE, OrchestrationStatusResult::SUCCESS, "") - ); EXPECT_CALL(mock_status, setIsConfigurationUpdated(A>()) ).WillOnce( Invoke( @@ -940,10 +936,6 @@ TEST_F(OrchestrationTest, orchestrationPolicyUpdate) ).WillOnce(Return(true)); EXPECT_CALL(mock_update_communication, setAddressExtenesion("/test")); EXPECT_CALL(mock_status, setLastUpdateAttempt()); - EXPECT_CALL( - mock_status, - setFieldStatus(OrchestrationStatusFieldType::LAST_UPDATE, OrchestrationStatusResult::SUCCESS, "") - ); EXPECT_CALL(mock_status, setIsConfigurationUpdated(A>()) ).WillOnce( Invoke( @@ -1013,7 +1005,7 @@ TEST_F(OrchestrationTest, loadOrchestrationPolicyFromBackup) ) ); - map empty_service_to_port_map; + map> empty_service_to_port_map; EXPECT_CALL(mock_service_controller, getServiceToPortMap()).WillRepeatedly(Return(empty_service_to_port_map)); EXPECT_CALL(rest, mockRestCall(RestAction::SHOW, "orchestration-status", _)); @@ -1108,14 +1100,6 @@ TEST_F(OrchestrationTest, manifestUpdate) ); EXPECT_CALL(mock_status, setLastUpdateAttempt()); - EXPECT_CALL( - mock_status, - setFieldStatus(OrchestrationStatusFieldType::LAST_UPDATE, OrchestrationStatusResult::SUCCESS, "") - ); - EXPECT_CALL( - mock_status, - setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::SUCCESS, "") - ); EXPECT_CALL(mock_status, setIsConfigurationUpdated(A>()) ).WillOnce( Invoke( @@ -1237,10 +1221,6 @@ TEST_F(OrchestrationTest, getBadPolicyUpdate) .WillOnce(ReturnRef(second_val) ); EXPECT_CALL(mock_status, setLastUpdateAttempt()); - EXPECT_CALL( - mock_status, - setFieldStatus(OrchestrationStatusFieldType::LAST_UPDATE, OrchestrationStatusResult::SUCCESS, "") - ); EXPECT_CALL(mock_status, setIsConfigurationUpdated(A>()) ).WillOnce( Invoke( @@ -1271,7 +1251,7 @@ TEST_F(OrchestrationTest, getBadPolicyUpdate) EXPECT_CALL( mock_service_controller, updateServiceConfiguration(string("policy path"), "", expected_data_types, "", "", _) - ).WillOnce(Return(Maybe(genError(string(""))))); + ).WillOnce(Return(Maybe(genError(string("Fail to load policy"))))); EXPECT_CALL(mock_ml, yield(A())) .WillOnce( @@ -1328,6 +1308,7 @@ TEST_F(OrchestrationTest, failedDownloadSettings) EXPECT_CALL(mock_update_communication, authenticateAgent()).WillOnce(Return(Maybe())); expectDetailsResolver(); + EXPECT_CALL(mock_manifest_controller, loadAfterSelfUpdate()).WillOnce(Return(false)); EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::SHA256, manifest_file_path)) .WillOnce(Return(manifest_checksum)); @@ -1359,22 +1340,10 @@ TEST_F(OrchestrationTest, failedDownloadSettings) ); EXPECT_CALL(mock_status, setLastUpdateAttempt()); - EXPECT_CALL( - mock_status, - setFieldStatus(OrchestrationStatusFieldType::LAST_UPDATE, OrchestrationStatusResult::SUCCESS, "") - ).Times(1); string manifest_err = "Critical Error: Agent/Gateway was not fully deployed on host 'hostname' " "and is not enforcing a security policy. Retry installation or contact Check Point support."; - EXPECT_CALL( - mock_status, - setFieldStatus( - OrchestrationStatusFieldType::MANIFEST, - OrchestrationStatusResult::FAILED, - manifest_err - ) - ).Times(1); EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(manifest_err)); EXPECT_CALL(mock_status, setIsConfigurationUpdated(A>()) @@ -1475,10 +1444,6 @@ TEST_P(OrchestrationTest, orchestrationFirstRun) .WillOnce(Return(data_checksum)); EXPECT_CALL(mock_status, setLastUpdateAttempt()); - EXPECT_CALL( - mock_status, - setFieldStatus(OrchestrationStatusFieldType::LAST_UPDATE, OrchestrationStatusResult::SUCCESS, "") - ); EXPECT_CALL(mock_status, setIsConfigurationUpdated(A>()) ).WillOnce( Invoke( @@ -1537,23 +1502,6 @@ TEST_P(OrchestrationTest, orchestrationFirstRun) } catch (const invalid_argument& e) {} EXPECT_CALL(mock_status, writeStatusToFile()); - vector reply; - bool is_named_query = GetParam(); - if (is_named_query) { - auto all_comps_status_reply = HealthCheckStatusEvent().performNamedQuery(); - for (auto &elem : all_comps_status_reply) { - reply.push_back(elem.second); - } - } else { - reply = HealthCheckStatusEvent().query(); - } - - ASSERT_EQ(reply.size(), 1); - EXPECT_EQ(reply[0].getCompName(), "Orchestration"); - EXPECT_EQ(reply[0].getStatus(), HealthCheckStatus::HEALTHY); - - HealthCheckStatusEvent().notify(); - orchestration_comp.fini(); } @@ -1721,10 +1669,6 @@ TEST_F(OrchestrationTest, dataUpdate) ); EXPECT_CALL(mock_status, setLastUpdateAttempt()); - EXPECT_CALL( - mock_status, - setFieldStatus(OrchestrationStatusFieldType::LAST_UPDATE, OrchestrationStatusResult::SUCCESS, "") - ); EXPECT_CALL(mock_status, setIsConfigurationUpdated(A>()) ).WillOnce( Invoke( diff --git a/components/security_apps/orchestration/service_controller/service_controller.cc b/components/security_apps/orchestration/service_controller/service_controller.cc index 9cca9f4..2b21a58 100755 --- a/components/security_apps/orchestration/service_controller/service_controller.cc +++ b/components/security_apps/orchestration/service_controller/service_controller.cc @@ -333,7 +333,7 @@ private: ReconfStatus getUpdatedReconfStatus(); Maybe getServiceDetails(const string &service_name); - map getServiceToPortMap(); + map> getServiceToPortMap(); template void serializeRegisterServices(Archive &ar) { ar(pending_services); } @@ -358,6 +358,7 @@ private: string filesystem_prefix; bool is_multi_tenant_env = false; set changed_policy_files; + ServiceDetails orchestration_service_details; I_OrchestrationTools *orchestration_tools = nullptr; I_MainLoop *mainloop = nullptr; @@ -374,8 +375,13 @@ public: for (auto const& entry: ports_map) { string service = entry.first; replace(service.begin(), service.end(), ' ', '-'); - output << service << ":"; - output << entry.second << ","; + output << service; + char delim = ':'; + for (PortNumber port : entry.second) { + output << delim << port; + delim = ','; + } + output << ";"; } ports_list = output.str(); } @@ -500,6 +506,7 @@ ServiceController::Impl::loadRegisteredServicesFromFile() stringstream ss(maybe_registered_services_str.unpack()); cereal::JSONInputArchive ar(ss); ar(cereal::make_nvp("Registered Services", pending_services)); + pending_services.erase("cp-nano-orchestration"); dbgInfo(D_SERVICE_CONTROLLER) << "Orchestration pending services loaded from file." @@ -529,16 +536,24 @@ ServiceController::Impl::writeRegisteredServicesToFile() "Orchestration registered services" ); + map registered_services_with_orch = registered_services; + if (orchestration_service_details.getServiceID() != "") { + registered_services_with_orch.emplace( + orchestration_service_details.getServiceID(), + orchestration_service_details + ); + } + ofstream ss(registered_services_file); cereal::JSONOutputArchive ar(ss); - ar(cereal::make_nvp("Registered Services", registered_services)); + ar(cereal::make_nvp("Registered Services", registered_services_with_orch)); dbgInfo(D_SERVICE_CONTROLLER) << "Orchestration registered services file has been updated. File: " << registered_services_file << ". Registered Services:"; - for (const auto &id_service_pair : registered_services) { + for (const auto &id_service_pair : registered_services_with_orch) { const auto &service = id_service_pair.second; dbgInfo(D_SERVICE_CONTROLLER) << "Service name: " @@ -591,20 +606,20 @@ ServiceController::Impl::cleanUpVirtualFiles() } } -map +map> ServiceController::Impl::getServiceToPortMap() { - map ports_map; + map> ports_map; for (auto const& entry: registered_services) { - const string &service = entry.first; + const string &service = entry.second.getServiceName(); PortNumber port = entry.second.getPort(); - ports_map[service] = port; + ports_map[service].push_back(port); } for (auto const& entry: pending_services) { - const string &service = entry.first; + const string &service = entry.second.getServiceName(); PortNumber port = entry.second.getPort(); - ports_map[service] = port; + ports_map[service].push_back(port); } return ports_map; @@ -624,6 +639,12 @@ ServiceController::Impl::registerServiceConfig( service_id ); + if (service_name == "cp-nano-orchestration") { + dbgTrace(D_SERVICE_CONTROLLER) << "Save the orchestration service details"; + orchestration_service_details = service_config; + return; + } + pending_services.erase(service_config.getServiceID()); pending_services.insert({service_config.getServiceID(), service_config}); refreshPendingServices(); diff --git a/components/security_apps/orchestration/service_controller/service_controller_ut/service_controller_ut.cc b/components/security_apps/orchestration/service_controller/service_controller_ut/service_controller_ut.cc index 5b50565..d576834 100755 --- a/components/security_apps/orchestration/service_controller/service_controller_ut/service_controller_ut.cc +++ b/components/security_apps/orchestration/service_controller/service_controller_ut/service_controller_ut.cc @@ -178,16 +178,17 @@ public: void expectNewConfigRequest(const string &response) { + Maybe res = HTTPResponse(HTTPStatusCode::HTTP_OK, response); EXPECT_CALL( mock_message, sendSyncMessage( HTTPMethod::POST, "/set-new-configuration", - HasSubstr("1.0.2"), + _, _, _ ) - ).WillOnce(Return(HTTPResponse(HTTPStatusCode::HTTP_OK, response))); + ).WillOnce(DoAll(SaveArg<2>(&version_body), Return(res))); } CPTestTempfile status_file; @@ -196,6 +197,7 @@ public: ::Environment env; ConfigComponent config; DeclarativePolicyUtils declarative_policy_utils; + string version_body; string configuration_dir; string policy_extension; string settings_extension; @@ -229,19 +231,21 @@ public: string old_version = "1.0.1"; string versions = - "[" - " {" - " \"id\": \"d8c3cc3c-f9df-83c8-f875-322dd8a0c161\"," - " \"name\": \"Linux Embedded Agents\"," - " \"version\": \"1.0.2\"" - " }" + "[\n" + " {\n" + " \"id\": \"d8c3cc3c-f9df-83c8-f875-322dd8a0c161\",\n" + " \"name\": \"Linux Embedded Agents\",\n" + " \"version\": \"1.0.2\",\n" + " \"profileType\": \"Embedded\"\n" + " }\n" "]"; string old_versions = "[" " {" " \"id\": \"d8c3cc3c-f9df-83c8-f875-322dd8a0c161\"," " \"name\": \"Linux Embedded Agents\"," - " \"version\": \"1.0.1\"" + " \"version\": \"1.0.1\"," + " \"profileType\": \"Embedded\"" " }" "]"; @@ -338,6 +342,23 @@ TEST_F(ServiceControllerTest, UpdateConfiguration) EXPECT_EQ(i_service_controller->getPolicyVersion(), version_value); EXPECT_EQ(i_service_controller->getPolicyVersions(), versions); EXPECT_EQ(i_service_controller->getUpdatePolicyVersion(), version_value); + + stringstream ver_ss; + ver_ss + << "{\n" + << " \"id\": 1,\n" + << " \"policy_version\": \"1.0.2,[\\n" + << " {\\n" + << " \\\"id\\\": \\\"d8c3cc3c-f9df-83c8-f875-322dd8a0c161\\\",\\n" + << " \\\"name\\\": \\\"Linux Embedded Agents\\\",\\n" + << " \\\"version\\\": \\\"1.0.2\\\",\\n" + << " \\\"profileType\\\": \\\"Embedded\\\"\\n" + << " }\\n" + << "]\"\n}"; + EXPECT_EQ( + version_body, + ver_ss.str() + ); } TEST_F(ServiceControllerTest, supportVersions) @@ -527,13 +548,13 @@ TEST_F(ServiceControllerTest, TimeOutUpdateConfiguration) TEST_F(ServiceControllerTest, readRegisteredServicesFromFile) { init(); - int family1_id3_port = 1111; + uint16_t family1_id3_port = 1111; string registered_services_json = "{\n" " \"Registered Services\": {\n" " \"family1_id3\": {\n" " \"Service name\": \"mock access control\",\n" " \"Service ID\": \"family1_id3\",\n" - " \"Service port\": 1111,\n" + " \"Service port\": " + to_string(family1_id3_port) + ",\n" " \"Relevant configs\": [\n" " \"non updated capability\",\n" " \"l4_firewall\"\n" @@ -573,7 +594,8 @@ TEST_F(ServiceControllerTest, readRegisteredServicesFromFile) service_controller.init(); auto services_to_port_map = i_service_controller->getServiceToPortMap(); - EXPECT_EQ(services_to_port_map.find("family1_id3")->second, family1_id3_port); + vector ports = {l4_firewall_service_port, family1_id3_port}; + EXPECT_EQ(services_to_port_map.find("mock access control")->second, ports); } TEST_F(ServiceControllerTest, noPolicyUpdate) @@ -1589,7 +1611,7 @@ TEST_F(ServiceControllerTest, testPortsRest) empty_json << "{}"; auto res = get_services_ports->performRestCall(empty_json); ASSERT_TRUE(res.ok()); - EXPECT_THAT(res.unpack(), HasSubstr("family1_id2:8888")); + EXPECT_THAT(res.unpack(), HasSubstr("mock-access-control:8888;")); } TEST_F(ServiceControllerTest, testMultitenantConfFiles) diff --git a/components/security_apps/orchestration/update_communication/fog_authenticator.cc b/components/security_apps/orchestration/update_communication/fog_authenticator.cc index ae475f5..c28ba86 100755 --- a/components/security_apps/orchestration/update_communication/fog_authenticator.cc +++ b/components/security_apps/orchestration/update_communication/fog_authenticator.cc @@ -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(); } diff --git a/components/security_apps/orchestration/update_communication/update_communication.cc b/components/security_apps/orchestration/update_communication/update_communication.cc index 95a3390..cebea89 100755 --- a/components/security_apps/orchestration/update_communication/update_communication.cc +++ b/components/security_apps/orchestration/update_communication/update_communication.cc @@ -32,6 +32,7 @@ using namespace std; USE_DEBUG_FLAG(D_ORCHESTRATOR); + class UpdateCommunication::Impl : public ServerRest, diff --git a/components/security_apps/orchestration/updates_process_reporter/CMakeLists.txt b/components/security_apps/orchestration/updates_process_reporter/CMakeLists.txt new file mode 100755 index 0000000..94357a8 --- /dev/null +++ b/components/security_apps/orchestration/updates_process_reporter/CMakeLists.txt @@ -0,0 +1 @@ +add_library(updates_process_reporter updates_process_event.cc updates_process_reporter.cc) diff --git a/components/security_apps/orchestration/updates_process_reporter/updates_process_event.cc b/components/security_apps/orchestration/updates_process_reporter/updates_process_event.cc new file mode 100644 index 0000000..b6afa5b --- /dev/null +++ b/components/security_apps/orchestration/updates_process_reporter/updates_process_event.cc @@ -0,0 +1,124 @@ +// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "updates_process_event.h" + +#include +#include + +#include "debug.h" + +using namespace std; + +USE_DEBUG_FLAG(D_UPDATES_PROCESS_REPORTER); + +UpdatesProcessEvent::UpdatesProcessEvent( + UpdatesProcessResult _result, + UpdatesConfigType _type, + UpdatesFailureReason _reason, + const std::string &_detail, + const std::string &_description) + : + result(_result), + type(_type), + reason(_reason), + detail(_detail), + description(_description) +{ + string report = + "Result: " + convertUpdateProcessResultToStr(result) + + ", Reason: " + convertUpdatesFailureReasonToStr(reason) + + ", Type: " + convertUpdatesConfigTypeToStr(type) + + ", Detail: " + detail + + ", Description: " + description; + dbgTrace(D_UPDATES_PROCESS_REPORTER) << "Updates process event: " << report; +} + +OrchestrationStatusFieldType +UpdatesProcessEvent::getStatusFieldType() const +{ + if (reason == UpdatesFailureReason::REGISTRATION) { + return OrchestrationStatusFieldType::REGISTRATION; + } + if (type == UpdatesConfigType::MANIFEST) { + return OrchestrationStatusFieldType::MANIFEST; + } + return OrchestrationStatusFieldType::LAST_UPDATE; +} + +OrchestrationStatusResult +UpdatesProcessEvent::getOrchestrationStatusResult() const +{ + return result == UpdatesProcessResult::SUCCESS ? + OrchestrationStatusResult::SUCCESS : + OrchestrationStatusResult::FAILED; +} + +string +UpdatesProcessEvent::parseDescription() const +{ + stringstream err; + if (description.empty() || result == UpdatesProcessResult::SUCCESS) return ""; + + switch (reason) { + case UpdatesFailureReason::CHECK_UPDATE: { + err << description; + break; + } + case UpdatesFailureReason::REGISTRATION: { + err << "Registration failed. Error: " << description; + break; + } + case UpdatesFailureReason::GET_UPDATE_REQUEST: { + err << "Failed to get update request. Error: " << description; + break; + } + case UpdatesFailureReason::DOWNLOAD_FILE : { + err << "Failed to download the file " << detail << ". Error: " << description; + break; + } + case UpdatesFailureReason::HANDLE_FILE : { + err << "Failed to handle the file " << detail << ". " << description; + break; + } + case UpdatesFailureReason::INSTALLATION_QUEUE : { + err << "Installation queue creation failed. Error: " << description; + break; + } + case UpdatesFailureReason::INSTALL_PACKAGE : { + err << "Failed to install the package " << detail << ". Error: " << description; + break; + } + case UpdatesFailureReason::CHECKSUM_UNMATCHED : { + err << "Checksums do not match for the file: " << detail << ". " << description; + break; + } + case UpdatesFailureReason::POLICY_CONFIGURATION : { + err << "Failed to configure policy version: " << detail << ". Error: " << description; + break; + } + case UpdatesFailureReason::POLICY_FOG_CONFIGURATION : { + err << "Failed to configure the fog address: " << detail << ". Error: " << description; + break; + } + case UpdatesFailureReason::ORCHESTRATION_SELF_UPDATE : { + err << description; + break; + } + case UpdatesFailureReason::NONE : { + err << description; + break; + } + } + return err.str(); +} diff --git a/components/security_apps/orchestration/updates_process_reporter/updates_process_reporter.cc b/components/security_apps/orchestration/updates_process_reporter/updates_process_reporter.cc new file mode 100644 index 0000000..c9269a0 --- /dev/null +++ b/components/security_apps/orchestration/updates_process_reporter/updates_process_reporter.cc @@ -0,0 +1,71 @@ +// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "updates_process_reporter.h" + +#include +#include + +#include "debug.h" +#include "log_generator.h" + +using namespace std; + +USE_DEBUG_FLAG(D_UPDATES_PROCESS_REPORTER); + +vector UpdatesProcessReporter::reports; + +void +UpdatesProcessReporter::upon(const UpdatesProcessEvent &event) +{ + if (event.getReason() == UpdatesFailureReason::CHECK_UPDATE) { + if (event.getResult() == UpdatesProcessResult::SUCCESS && reports.empty()) { + dbgTrace(D_UPDATES_PROCESS_REPORTER) << "Update proccess finished successfully"; + return; + } + dbgTrace(D_UPDATES_PROCESS_REPORTER) << "Update proccess finished with errors"; + reports.emplace_back( + UpdatesProcessReport( + event.getResult(), + event.getType(), + event.getReason(), + event.parseDescription() + ) + ); + sendReoprt(); + return; + } + if (event.getResult() == UpdatesProcessResult::SUCCESS || event.getResult() == UpdatesProcessResult::UNSET) return; + reports.emplace_back( + UpdatesProcessReport(event.getResult(), event.getType(), event.getReason(), event.parseDescription()) + ); +} + +void +UpdatesProcessReporter::sendReoprt() +{ + stringstream all_reports; + all_reports << "Updates process reports:" << endl; + for (const auto &report : reports) { + all_reports << report.toString() << endl; + } + reports.clear(); + dbgTrace(D_UPDATES_PROCESS_REPORTER) << "Sending updates process report: " << endl << all_reports.str(); + LogGen( + "Updates process report", + ReportIS::Audience::INTERNAL, + ReportIS::Severity::HIGH, + ReportIS::Priority::HIGH, + ReportIS::Tags::ORCHESTRATOR + ) << LogField("eventMessage", all_reports.str()); +} diff --git a/components/security_apps/waap/waap_clib/DeepParser.cc b/components/security_apps/waap/waap_clib/DeepParser.cc index 0dcf014..3735778 100755 --- a/components/security_apps/waap/waap_clib/DeepParser.cc +++ b/components/security_apps/waap/waap_clib/DeepParser.cc @@ -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 ); diff --git a/components/security_apps/waap/waap_clib/ParserBase.h b/components/security_apps/waap/waap_clib/ParserBase.h index 4d7d9e3..0e3265e 100755 --- a/components/security_apps/waap/waap_clib/ParserBase.h +++ b/components/security_apps/waap/waap_clib/ParserBase.h @@ -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 diff --git a/components/security_apps/waap/waap_clib/Serializator.cc b/components/security_apps/waap/waap_clib/Serializator.cc index b80e5f3..5b982b9 100755 --- a/components/security_apps/waap/waap_clib/Serializator.cc +++ b/components/security_apps/waap/waap_clib/Serializator.cc @@ -727,7 +727,6 @@ void SerializeToLocalAndRemoteSyncBase::syncWorker() "sync notification for '" + m_assetId + "'", ReportIS::AudienceTeam::WAAP, syncNotification, - false, MessageCategory::GENERIC, ReportIS::Tags::WAF, ReportIS::Notification::SYNC_LEARNING diff --git a/components/security_apps/waap/waap_clib/WaapOverride.h b/components/security_apps/waap/waap_clib/WaapOverride.h index 2d315ff..2d5d3bd 100755 --- a/components/security_apps/waap/waap_clib/WaapOverride.h +++ b/components/security_apps/waap/waap_clib/WaapOverride.h @@ -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(); 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(); 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 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 @@ -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 m_behaviors; std::string m_id; + bool isValid; }; class Policy { @@ -270,6 +298,10 @@ public: for (std::vector::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); diff --git a/components/security_apps/waap/waap_clib/WaapOverrideFunctor.cc b/components/security_apps/waap/waap_clib/WaapOverrideFunctor.cc index 1ef91de..0bf93e0 100755 --- a/components/security_apps/waap/waap_clib/WaapOverrideFunctor.cc +++ b/components/security_apps/waap/waap_clib/WaapOverrideFunctor.cc @@ -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; } diff --git a/components/security_apps/waap/waap_clib/Waf2Engine.cc b/components/security_apps/waap/waap_clib/Waf2Engine.cc index 22c3d6b..e282ea4 100755 --- a/components/security_apps/waap/waap_clib/Waf2Engine.cc +++ b/components/security_apps/waap/waap_clib/Waf2Engine.cc @@ -1516,6 +1516,7 @@ Waf2Transaction::decideAfterHeaders() return finalizeDecision(sitePolicy, shouldBlock); } + // Note: the only user of the transactionResult structure filled by this method is waap_automation. // TODO: Consider removing this parameter (and provide access to this information by other means) int diff --git a/components/security_apps/waap/waap_clib/Waf2EngineGetters.cc b/components/security_apps/waap/waap_clib/Waf2EngineGetters.cc index 89b420a..90d114d 100755 --- a/components/security_apps/waap/waap_clib/Waf2EngineGetters.cc +++ b/components/security_apps/waap/waap_clib/Waf2EngineGetters.cc @@ -567,12 +567,11 @@ Waap::Override::State Waf2Transaction::getOverrideState(IWaapConfig* sitePolicy) extractEnvSourceIdentifier(); - Waap::Override::State overrideStateResponse; if (overridePolicy) { // later we will run response overrides - overrideStateResponse.applyOverride(*overridePolicy, WaapOverrideFunctor(*this), m_matchedOverrideIds, false); + m_overrideState.applyOverride(*overridePolicy, WaapOverrideFunctor(*this), m_matchedOverrideIds, false); } m_isHeaderOverrideScanRequired = false; - return overrideStateResponse; + return m_overrideState; } Waf2TransactionFlags &Waf2Transaction::getTransactionFlags() diff --git a/core/agent_core_utilities/agent_core_utilities.cc b/core/agent_core_utilities/agent_core_utilities.cc index 2483f8a..4cd74ee 100644 --- a/core/agent_core_utilities/agent_core_utilities.cc +++ b/core/agent_core_utilities/agent_core_utilities.cc @@ -175,7 +175,7 @@ copyFile(const string &src, const string &dest, bool overide_if_exists, mode_t p struct stat stat_buf; int source_fd = open(src.c_str(), O_RDONLY); fstat(source_fd, &stat_buf); - int dest_fd = open(dest.c_str(), O_WRONLY | O_CREAT, permission); + int dest_fd = open(dest.c_str(), O_WRONLY | O_CREAT | O_TRUNC, permission); int bytes_copied = 1; while (bytes_copied > 0) { static const int buf_size = 4096*1000; diff --git a/core/agent_core_utilities/agent_core_utilities_ut/agent_core_utilities_ut.cc b/core/agent_core_utilities/agent_core_utilities_ut/agent_core_utilities_ut.cc index bbf86ac..979f457 100644 --- a/core/agent_core_utilities/agent_core_utilities_ut/agent_core_utilities_ut.cc +++ b/core/agent_core_utilities/agent_core_utilities_ut/agent_core_utilities_ut.cc @@ -37,8 +37,11 @@ TEST_F(AgentCoreUtilUT, filesTest) EXPECT_FALSE(NGEN::Filesystem::exists("/i/am/not/a/real/path")); const vector lines{"i am a line in the text file", "i am iron man"}; + const vector lines_b{"i am a line 2 in the text file", "i am iron man 2", "hello again"}; CPTestTempfile test_file(lines); + CPTestTempfile test_file_b(lines_b); ASSERT_TRUE(NGEN::Filesystem::exists(test_file.fname)); + ASSERT_TRUE(NGEN::Filesystem::exists(test_file_b.fname)); string output_orig = test_file.readFile(); string new_path = test_file.fname + ".new"; @@ -46,6 +49,7 @@ TEST_F(AgentCoreUtilUT, filesTest) ASSERT_TRUE(NGEN::Filesystem::exists(new_path)); ASSERT_FALSE(NGEN::Filesystem::copyFile(test_file.fname, new_path, false)); ASSERT_TRUE(NGEN::Filesystem::copyFile(test_file.fname, new_path, true)); + ASSERT_TRUE(NGEN::Filesystem::copyFile(test_file.fname, test_file_b.fname, true)); string output_new; { ifstream new_file_stream(new_path); @@ -55,11 +59,20 @@ TEST_F(AgentCoreUtilUT, filesTest) output_new = buffer.str(); } + string output_test_b; + ifstream new_file_stream(test_file_b.fname); + ASSERT_TRUE(new_file_stream.good()); + stringstream buffer; + buffer << new_file_stream.rdbuf(); + output_test_b = buffer.str(); + EXPECT_EQ(output_orig, output_new); + EXPECT_EQ(output_orig, output_test_b); EXPECT_THAT(output_new, HasSubstr("i am a line in the text file")); EXPECT_THAT(output_new, HasSubstr("i am iron man")); EXPECT_TRUE(NGEN::Filesystem::deleteFile(test_file.fname)); EXPECT_TRUE(NGEN::Filesystem::deleteFile(new_path)); + EXPECT_TRUE(NGEN::Filesystem::deleteFile(test_file_b.fname)); EXPECT_FALSE(NGEN::Filesystem::exists(test_file.fname)); EXPECT_FALSE(NGEN::Filesystem::exists(new_path)); } diff --git a/core/config/config.cc b/core/config/config.cc index 84b5c6e..821fc7e 100644 --- a/core/config/config.cc +++ b/core/config/config.cc @@ -348,14 +348,12 @@ ConfigComponent::Impl::init() if (!Singleton::exists()) return; auto mainloop = Singleton::Consume::by(); - if (executable_name != "cp-nano-orchestration") { - mainloop->addOneTimeRoutine( - I_MainLoop::RoutineType::System, - [this] () { periodicRegistrationRefresh(); }, - "Configuration update registration", - false - ); - } + mainloop->addOneTimeRoutine( + I_MainLoop::RoutineType::System, + [this] () { periodicRegistrationRefresh(); }, + "Configuration update registration", + false + ); } static bool diff --git a/core/debug_is/debug.cc b/core/debug_is/debug.cc index 51a9a5c..cbc603a 100644 --- a/core/debug_is/debug.cc +++ b/core/debug_is/debug.cc @@ -234,6 +234,55 @@ public: static DebugConfiguration default_config; +class ChangeDebugConfiguration : public ServerRest +{ +public: + void + doCall() override + { + string debug_config_file_name = Debug::getExecutableName(); + if (debug_config_file_name == "") { + output = "Error. Cannot get debug config file path"; + return; + } + string debug_config_file_path = getConfigurationWithDefault( + getFilesystemPathConfig() + "/conf/" + debug_config_file_name + "-debug-conf.json", + "Debug I/S", + "Debug conf file path" + ); + try { + ifstream input_stream(debug_config_file_path); + if (!input_stream) { + output = "Error. Cannot open the debug conf file: " + debug_config_file_path; + return; + } + cereal::JSONInputArchive ar(input_stream); + Debug::prepareConfig(); + vector debug_config; + try { + ar(cereal::make_nvp("Debug", debug_config)); + } catch (cereal::Exception &e) { + output = "Error. Failed loading debug conf file, error: " + string(e.what()); + Debug::abortConfig(); + return; + } + input_stream.close(); + setConfiguration(debug_config[0], "Debug"); + Debug::commitConfig(); + output = "New debug configuration set succesfully"; + } catch (ifstream::failure &f) { + output = + "Error. Cannot open the debug conf file " + + debug_config_file_path + + ", error: " + + string(f.what()); + } + } + +private: + S2C_PARAM(string, output); +}; + // LCOV_EXCL_START - function is covered in unit-test, but not detected bt gcov Debug::Debug( const string &file_name, @@ -446,6 +495,7 @@ Debug::preload() { registerExpectedConfiguration("Debug"); registerExpectedConfiguration("Debug I/S", "Fog Debug URI"); + registerExpectedConfiguration("Debug I/S", "Debug conf file path"); registerExpectedConfiguration("Debug I/S", "Enable bulk of debugs"); registerExpectedConfiguration("Debug I/S", "Debug bulk size"); registerExpectedConfiguration("Debug I/S", "Debug bulk sending interval in msec"); @@ -467,22 +517,18 @@ Debug::init() mainloop = Singleton::Consume::by(); env = Singleton::Consume::by(); - auto executable = env->get("Executable Name"); - - if (executable.ok() && *executable != "") { - string default_debug_output_file_path = *executable; - auto file_path_end = default_debug_output_file_path.find_last_of("/"); - if (file_path_end != string::npos) { - default_debug_file_stream_path = default_debug_output_file_path.substr(file_path_end + 1); - } - auto file_sufix_start = default_debug_file_stream_path.find_first_of("."); - if (file_sufix_start != string::npos) { - default_debug_file_stream_path = default_debug_file_stream_path.substr(0, file_sufix_start); - } - + default_debug_file_stream_path = getExecutableName(); + if (default_debug_file_stream_path != "") { string log_files_prefix = getLogFilesPathConfig(); default_debug_file_stream_path = log_files_prefix + "/nano_agent/" + default_debug_file_stream_path + ".dbg"; } + + if (Singleton::exists()) { + Singleton::Consume::by()->addRestCall( + RestAction::SET, + "change-debug-config" + ); + } } void @@ -706,6 +752,27 @@ Debug::findDebugFilePrefix(const string &file_name) return ""; } +string +Debug::getExecutableName() +{ + auto executable = env->get("Executable Name"); + if (!executable.ok() || *executable == "") { + return ""; + } + + string executable_name = *executable; + auto file_path_end = executable_name.find_last_of("/"); + if (file_path_end != string::npos) { + executable_name = executable_name.substr(file_path_end + 1); + } + auto file_sufix_start = executable_name.find_first_of("."); + if (file_sufix_start != string::npos) { + executable_name = executable_name.substr(0, file_sufix_start); + } + + return executable_name; +} + void Debug::addActiveStream(const string &name) { diff --git a/core/debug_is/debug_ex.h b/core/debug_is/debug_ex.h index 920fc8d..2fcfda0 100644 --- a/core/debug_is/debug_ex.h +++ b/core/debug_is/debug_ex.h @@ -21,6 +21,7 @@ #include "report/report.h" #include "i_agent_details.h" #include "i_environment.h" +#include "i_rest_api.h" #include "i_mainloop.h" #include "report/report_bulks.h" diff --git a/core/debug_is/debug_is_ut/debug-ut-debug-conf.json b/core/debug_is/debug_is_ut/debug-ut-debug-conf.json new file mode 100644 index 0000000..ec0993f --- /dev/null +++ b/core/debug_is/debug_is_ut/debug-ut-debug-conf.json @@ -0,0 +1,13 @@ +{ + "Debug": [ + { + "Streams": [ + { + "D_ALL": "Info", + "D_FW": "Debug", + "Output": "/var/log/nano_agent/cp-nano-orchestration.dbg" + } + ] + } + ] +} diff --git a/core/debug_is/debug_is_ut/debug_ut.cc b/core/debug_is/debug_is_ut/debug_ut.cc index fe0357c..c533a5a 100644 --- a/core/debug_is/debug_is_ut/debug_ut.cc +++ b/core/debug_is/debug_is_ut/debug_ut.cc @@ -14,6 +14,7 @@ #include "mock/mock_messaging.h" #include "mock/mock_mainloop.h" #include "mock/mock_environment.h" +#include "mock/mock_rest_api.h" #include "mock/mock_instance_awareness.h" using namespace std; @@ -551,7 +552,6 @@ public: Debug::setNewDefaultStdout(&capture_debug); } - ~DebugConfigTest() { loadConfiguration(""); @@ -583,10 +583,19 @@ public: Singleton::Consume::from(conf)->loadConfiguration(configuration); } + bool + setDebugConfig(const unique_ptr &p) + { + set_debug_config = p->getRest(); + return true; + } + ConfigComponent conf; ::Environment env; stringstream capture_debug; StrictMock mock_agent_details; + NiceMock mock_rest; + unique_ptr set_debug_config; }; TEST_F(DebugConfigTest, basic_configuration) @@ -786,6 +795,54 @@ TEST_F(DebugConfigTest, fail_configuration) EXPECT_FALSE(loadConfiguration(debug_config)); } +TEST_F(DebugConfigTest, testSetConfig) +{ + NiceMock mock_mainloop; + StrictMock mock_time; + Debug::setUnitTestFlag(D_FW, Debug::DebugLevel::WARNING); + EXPECT_TRUE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::ERROR)); + EXPECT_FALSE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::INFO)); + EXPECT_FALSE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::DEBUG)); + EXPECT_FALSE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::TRACE)); + + EXPECT_CALL(mock_rest, mockRestCall(RestAction::SET, "change-debug-config", _)) + .WillOnce(WithArg<2>(Invoke(this, &DebugConfigTest::setDebugConfig)) + ); + Maybe error_id = genError("no id"); + EXPECT_CALL(mock_mainloop, getCurrentRoutineId()).WillRepeatedly(Return(error_id)); + EXPECT_CALL(mock_time, getWalltimeStr()).WillRepeatedly(Return(string(""))); + + EXPECT_CALL(mock_rest, mockRestCall(RestAction::ADD, "declare-boolean-variable", _)).WillOnce(Return(true)); + + env.preload(); + Singleton::Consume::from(env)->registerValue("Executable Name", "debug-ut"); + env.init(); + + Debug::init(); + + setConfiguration( + cptestFnameInSrcDir(string("debug-ut-debug-conf.json")), + string("Debug I/S"), + string("Debug conf file path") + ); + + stringstream ss("{}"); + Maybe maybe_res = set_debug_config->performRestCall(ss); + ASSERT_TRUE(maybe_res.ok()); + EXPECT_EQ(maybe_res.unpack(), "{\n \"output\": \"New debug configuration set succesfully\"\n}"); + + EXPECT_TRUE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::ERROR)); + EXPECT_TRUE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::INFO)); + EXPECT_TRUE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::DEBUG)); + EXPECT_FALSE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::TRACE)); + Debug::setUnitTestFlag(D_FW, Debug::DebugLevel::WARNING); // Reset debug level so it won't effect other tests + EXPECT_TRUE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::ERROR)); + EXPECT_FALSE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::INFO)); + EXPECT_FALSE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::DEBUG)); + EXPECT_FALSE(Debug::isFlagAtleastLevel(D_FW, Debug::DebugLevel::TRACE)); + Debug::fini(); +} + ACTION(InvokeMainLoopCB) { arg1(); diff --git a/core/environment/environment.cc b/core/environment/environment.cc index d0278b3..ec8a0e5 100644 --- a/core/environment/environment.cc +++ b/core/environment/environment.cc @@ -58,7 +58,6 @@ public: string getCurrentTrace() const override; string getCurrentSpan() const override; - string getCurrentHeaders() override; map getCurrentHeadersMap() override; void startNewTrace(bool new_span, const string &_trace_id) override; @@ -239,34 +238,6 @@ Environment::Impl::getCurrentSpan() const return ""; } -string -Environment::Impl::getCurrentHeaders() -{ - string tracing_headers; - auto trace_id = getCurrentTrace(); - if (!trace_id.empty()) { - tracing_headers += "X-Trace-Id: " + trace_id + "\r\n"; - } else { - string correlation_id_string = "00000000-0000-0000-0000-000000000000"; - try { - boost::uuids::random_generator uuid_random_gen; - correlation_id_string = boost::uuids::to_string(uuid_random_gen()); - } catch (const boost::uuids::entropy_error &e) { - dbgTrace(D_ENVIRONMENT) - << "Failed to generate random correlation id - entropy exception. Exception: " - << e.what(); - tracing_status = TracingStatus::DISABLED; - } - tracing_headers += "X-Trace-Id: " + correlation_id_string + "\r\n"; - } - - auto span_id = getCurrentSpan(); - if (!span_id.empty()) { - tracing_headers += "X-Span-Id: " + span_id + "\r\n"; - } - return tracing_headers; -} - map Environment::Impl::getCurrentHeadersMap() { @@ -292,6 +263,21 @@ Environment::Impl::getCurrentHeadersMap() if (!span_id.empty()) { tracing_headers["X-Span-Id"] = span_id; } + + auto exec_name = get("Executable Name"); + if (exec_name.ok() && *exec_name != "") { + string executable_name = *exec_name; + auto file_path_end = executable_name.find_last_of("/"); + if (file_path_end != string::npos) { + executable_name = executable_name.substr(file_path_end + 1); + } + auto file_sufix_start = executable_name.find_first_of("."); + if (file_sufix_start != string::npos) { + executable_name = executable_name.substr(0, file_sufix_start); + } + tracing_headers["X-Calling-Service"] = executable_name; + } + return tracing_headers; } diff --git a/core/environment/environment_ut/tracing_ut.cc b/core/environment/environment_ut/tracing_ut.cc index 33ad799..ebf0a1d 100644 --- a/core/environment/environment_ut/tracing_ut.cc +++ b/core/environment/environment_ut/tracing_ut.cc @@ -345,12 +345,16 @@ public: TEST_F(TracingCompRoutinesTest, 2SpansDifFlow) { I_MainLoop::Routine routine = [&] () { + string service_name = "test-service-name"; + i_env->registerValue("Executable Name", service_name); + i_env->startNewTrace(true, "a687b388-1108-4083-9852-07c33b1074e9"); trace_id = i_env->getCurrentTrace(); span_id = i_env->getCurrentSpan(); - string headers = i_env->getCurrentHeaders(); - EXPECT_THAT(headers, HasSubstr("X-Trace-Id: " + trace_id)); - EXPECT_THAT(headers, HasSubstr("X-Span-Id: " + span_id)); + auto headers = i_env->getCurrentHeadersMap(); + EXPECT_THAT(headers["X-Trace-Id"], trace_id); + EXPECT_THAT(headers["X-Span-Id"], span_id); + EXPECT_THAT(headers["X-Calling-Service"], service_name); EXPECT_EQ(trace_id, "a687b388-1108-4083-9852-07c33b1074e9"); EXPECT_NE("", i_env->getCurrentSpan()); diff --git a/core/include/general/debug.h b/core/include/general/debug.h index c62d92f..100585b 100644 --- a/core/include/general/debug.h +++ b/core/include/general/debug.h @@ -30,6 +30,7 @@ class I_Environment; class I_InstanceAwareness; class I_Encryptor; class I_AgentDetails; +class I_RestApi; class I_SignalHandler; namespace Config { enum class Errors; } @@ -44,6 +45,7 @@ class Debug Singleton::Consume, Singleton::Consume, Singleton::Consume, + Singleton::Consume, Singleton::Consume { public: @@ -178,6 +180,7 @@ public: static void setUnitTestFlag(DebugFlags flag, DebugLevel level); static std::string findDebugFilePrefix(const std::string &file_name); + static std::string getExecutableName(); private: template diff --git a/core/include/internal/messaging.h b/core/include/internal/messaging.h index 3051aaf..6de8566 100644 --- a/core/include/internal/messaging.h +++ b/core/include/internal/messaging.h @@ -26,6 +26,7 @@ #include "i_time_get.h" #include "i_encryptor.h" #include "i_shell_cmd.h" +#include "i_rest_api.h" #include "i_instance_awareness.h" #include "config.h" @@ -41,6 +42,7 @@ class Messaging Singleton::Consume, Singleton::Consume, Singleton::Consume, + Singleton::Consume, Singleton::Consume { public: diff --git a/core/include/services_sdk/interfaces/i_environment.h b/core/include/services_sdk/interfaces/i_environment.h index 88f0f04..5deb7a2 100644 --- a/core/include/services_sdk/interfaces/i_environment.h +++ b/core/include/services_sdk/interfaces/i_environment.h @@ -79,7 +79,6 @@ public: virtual std::string getCurrentTrace() const = 0; virtual std::string getCurrentSpan() const = 0; - virtual std::string getCurrentHeaders() = 0; virtual std::map getCurrentHeadersMap() = 0; virtual void startNewTrace(bool new_span = true, const std::string &_trace_id = std::string()) = 0; virtual void startNewSpan( diff --git a/core/include/services_sdk/interfaces/i_intelligence_is_v2.h b/core/include/services_sdk/interfaces/i_intelligence_is_v2.h index a7d8dbf..b967217 100644 --- a/core/include/services_sdk/interfaces/i_intelligence_is_v2.h +++ b/core/include/services_sdk/interfaces/i_intelligence_is_v2.h @@ -46,11 +46,17 @@ public: const std::vector &query_requests, bool is_pretty, bool is_bulk, + bool is_proxy, const MessageMetadata &req_md ) const = 0; virtual Maybe - getResponse(const QueryRequest &query_request, bool is_pretty, const MessageMetadata &req_md) const = 0; + getResponse( + const QueryRequest &query_request, + bool is_pretty, + bool is_proxy, + const MessageMetadata &req_md + ) const = 0; template Maybe>> @@ -58,6 +64,7 @@ public: QueryRequest &query_request, bool ignore_in_progress = false, bool is_pretty = true, + bool is_proxy = false, MessageMetadata req_md = MessageMetadata("", 0) ); @@ -66,6 +73,7 @@ public: queryIntelligence( std::vector &query_requests, bool is_pretty = true, + bool is_proxy = false, MessageMetadata req_md = MessageMetadata("", 0) ); diff --git a/core/include/services_sdk/interfaces/intelligence_is_v2/intelligence_interface_impl.h b/core/include/services_sdk/interfaces/intelligence_is_v2/intelligence_interface_impl.h index 32e852c..a65bd58 100644 --- a/core/include/services_sdk/interfaces/intelligence_is_v2/intelligence_interface_impl.h +++ b/core/include/services_sdk/interfaces/intelligence_is_v2/intelligence_interface_impl.h @@ -24,10 +24,11 @@ I_Intelligence_IS_V2::queryIntelligence( QueryRequest &query_request, bool ignore_in_progress, bool is_pretty, + bool is_proxy, MessageMetadata req_md ) { - auto response = getResponse(query_request, is_pretty, req_md); + auto response = getResponse(query_request, is_pretty, is_proxy, req_md); if (!response.ok()) return response.passErr(); auto serializable_response = response->getSerializableResponse(); @@ -49,10 +50,11 @@ Maybe>>>> I_Intelligence_IS_V2::queryIntelligence( std::vector &query_requests, bool is_pretty, + bool is_proxy, MessageMetadata req_md ) { - auto res = getResponse(query_requests, is_pretty, true, req_md); + auto res = getResponse(query_requests, is_pretty, true, is_proxy, req_md); if (!res.ok()) return res.passErr(); return res->getBulkData(); diff --git a/core/include/services_sdk/interfaces/intelligence_is_v2/query_filter_v2.h b/core/include/services_sdk/interfaces/intelligence_is_v2/query_filter_v2.h index f8ca1d5..f599260 100644 --- a/core/include/services_sdk/interfaces/intelligence_is_v2/query_filter_v2.h +++ b/core/include/services_sdk/interfaces/intelligence_is_v2/query_filter_v2.h @@ -73,6 +73,7 @@ public: SerializableQueryFilter(Condition condition_type, const std::string &key, const std::string &value); SerializableQueryFilter(Condition condition_type, const std::string &key, const int64_t &value); SerializableQueryFilter(Condition condition_type, const std::string &key, const std::vector &value); + SerializableQueryFilter(const SerializableQueryCondition &condition); void save(cereal::JSONOutputArchive &ar) const; diff --git a/core/include/services_sdk/interfaces/mock/mock_environment.h b/core/include/services_sdk/interfaces/mock/mock_environment.h index 3f08bf8..f36c2c8 100644 --- a/core/include/services_sdk/interfaces/mock/mock_environment.h +++ b/core/include/services_sdk/interfaces/mock/mock_environment.h @@ -28,7 +28,6 @@ public: MOCK_CONST_METHOD0(getCurrentTrace, std::string()); MOCK_CONST_METHOD0(getCurrentSpan, std::string()); - MOCK_METHOD0(getCurrentHeaders, std::string()); MOCK_METHOD0(getCurrentHeadersMap, std::map()); MOCK_METHOD2(startNewTrace, void(bool, const std::string &)); MOCK_METHOD3(startNewSpan, void(Span::ContextType, const std::string &, const std::string &)); diff --git a/core/include/services_sdk/interfaces/mock/mock_intelligence.h b/core/include/services_sdk/interfaces/mock/mock_intelligence.h index dade4ee..b126997 100644 --- a/core/include/services_sdk/interfaces/mock/mock_intelligence.h +++ b/core/include/services_sdk/interfaces/mock/mock_intelligence.h @@ -26,21 +26,26 @@ public: MOCK_CONST_METHOD1(sendInvalidation, bool(const Invalidation &invalidation)); MOCK_METHOD2(registerInvalidation, Maybe(const Invalidation &invalidation, const InvalidationCb &callback)); MOCK_METHOD1(unregisterInvalidation, void(uint id)); - MOCK_CONST_METHOD4( + MOCK_CONST_METHOD5( getResponse, Maybe( const std::vector &query_requests, bool is_pretty, bool is_bulk, + bool is_proxy, const MessageMetadata &req_md ) ); - MOCK_CONST_METHOD3( + MOCK_CONST_METHOD4( getResponse, - Maybe(const QueryRequest &query_request, bool is_pretty, const MessageMetadata &req_md) + Maybe( + const QueryRequest &query_request, + bool is_pretty, + bool is_proxy, + const MessageMetadata &req_md + ) ); MOCK_CONST_METHOD0(getIsOfflineOnly, bool(void)); - MOCK_CONST_METHOD1(getOfflineInfoString, Maybe(const SerializableQueryFilter &query)); }; #endif // __MOCK_INTELLIGENCE_H__ diff --git a/core/include/services_sdk/resources/component_is/components_list_impl.h b/core/include/services_sdk/resources/component_is/components_list_impl.h index c043257..e9c6c48 100644 --- a/core/include/services_sdk/resources/component_is/components_list_impl.h +++ b/core/include/services_sdk/resources/component_is/components_list_impl.h @@ -209,13 +209,13 @@ class ComponentListCore ShellCmd, GenericMetric, Messaging, + MainloopComponent, ConfigComponent, InstanceAwareness, IntelligenceComponentV2, AgentDetails, LoggingComp, TimeProxyComponent, - MainloopComponent, SignalHandler, RestServer, Encryptor, diff --git a/core/include/services_sdk/resources/debug_flags.h b/core/include/services_sdk/resources/debug_flags.h index e11287c..cc992c8 100644 --- a/core/include/services_sdk/resources/debug_flags.h +++ b/core/include/services_sdk/resources/debug_flags.h @@ -142,6 +142,7 @@ DEFINE_FLAG(D_COMPONENT, D_ALL) DEFINE_FLAG(D_LOCAL_POLICY, D_ORCHESTRATOR) DEFINE_FLAG(D_NGINX_POLICY, D_ORCHESTRATOR) DEFINE_FLAG(D_SERVICE_CONTROLLER, D_ORCHESTRATOR) + DEFINE_FLAG(D_UPDATES_PROCESS_REPORTER, D_ORCHESTRATOR) DEFINE_FLAG(D_GRADUAL_DEPLOYMENT, D_COMPONENT) DEFINE_FLAG(D_SDWAN, D_COMPONENT) diff --git a/core/include/services_sdk/resources/health_check_status/health_check_status.h b/core/include/services_sdk/resources/health_check_status/health_check_status.h index 7111e0b..9048a7a 100644 --- a/core/include/services_sdk/resources/health_check_status/health_check_status.h +++ b/core/include/services_sdk/resources/health_check_status/health_check_status.h @@ -89,11 +89,4 @@ private: std::map extended_status = {}; }; -class HealthCheckStatusEvent : public Event -{ -public: - HealthCheckStatusEvent() {} - ~HealthCheckStatusEvent() {} -}; - #endif // __HEALTH_CHECK_STATUS_H__ diff --git a/core/include/services_sdk/resources/report/report_enums.h b/core/include/services_sdk/resources/report/report_enums.h index 7923ad3..6309d89 100644 --- a/core/include/services_sdk/resources/report/report_enums.h +++ b/core/include/services_sdk/resources/report/report_enums.h @@ -69,6 +69,8 @@ enum class Tags { NGINX_PROXY_MANAGER, WEB_SERVER_APISIX, DEPLOYMENT_DOCKER, + WEB_SERVER_SWAG, + WEB_SERVER_NGINX_UNIFIED, COUNT }; diff --git a/core/intelligence_is_v2/include/intelligence_request.h b/core/intelligence_is_v2/include/intelligence_request.h index 6725cce..4404d1e 100644 --- a/core/intelligence_is_v2/include/intelligence_request.h +++ b/core/intelligence_is_v2/include/intelligence_request.h @@ -29,10 +29,11 @@ public: const std::vector &queries, bool is_pretty, bool is_bulk, + bool _is_proxy, const MessageMetadata &req_md ) : - queries(queries), is_pretty(is_pretty), is_bulk(is_bulk), req_md(req_md) + queries(queries), is_pretty(is_pretty), is_bulk(is_bulk), is_proxy(_is_proxy), req_md(req_md) {} Maybe checkAssetsLimit() const; @@ -51,6 +52,7 @@ private: const std::vector &queries; bool is_pretty = true; bool is_bulk = false; + bool is_proxy = false; Maybe response_from_fog = genError("Uninitialized"); const MessageMetadata &req_md; }; diff --git a/core/intelligence_is_v2/intelligence_comp_v2.cc b/core/intelligence_is_v2/intelligence_comp_v2.cc index 3b4dfaf..70fdcf7 100644 --- a/core/intelligence_is_v2/intelligence_comp_v2.cc +++ b/core/intelligence_is_v2/intelligence_comp_v2.cc @@ -340,10 +340,11 @@ public: const vector &query_requests, bool is_pretty, bool is_bulk, + bool is_proxy, const MessageMetadata &req_md ) const override { - IntelligenceRequest intelligence_req(query_requests, is_pretty, is_bulk, req_md); + IntelligenceRequest intelligence_req(query_requests, is_pretty, is_bulk, is_proxy, req_md); if (!intelligence_req.checkAssetsLimit().ok()) return intelligence_req.checkAssetsLimit().passErr(); if (!intelligence_req.checkMinConfidence().ok()) return intelligence_req.checkMinConfidence().passErr(); if (intelligence_req.isPagingActivated()) { @@ -357,10 +358,15 @@ public: } Maybe - getResponse(const QueryRequest &query_request, bool is_pretty, const MessageMetadata &req_md) const override + getResponse( + const QueryRequest &query_request, + bool is_pretty, + bool is_proxy, + const MessageMetadata &req_md + ) const override { vector queries = {query_request}; - return getResponse(queries, is_pretty, false, req_md); + return getResponse(queries, is_pretty, false, is_proxy, req_md); } private: diff --git a/core/intelligence_is_v2/intelligence_is_v2_ut/intelligence_comp_v2_ut.cc b/core/intelligence_is_v2/intelligence_is_v2_ut/intelligence_comp_v2_ut.cc index 53cf7ea..18578ea 100644 --- a/core/intelligence_is_v2/intelligence_is_v2_ut/intelligence_comp_v2_ut.cc +++ b/core/intelligence_is_v2/intelligence_is_v2_ut/intelligence_comp_v2_ut.cc @@ -131,7 +131,7 @@ TEST_F(IntelligenceComponentMockTest, getResponseErrorTest) QueryRequest request(Condition::EQUALS, "category", "cloud", true); Maybe res_error = genError("Test error"); - EXPECT_CALL(intelligence_mock, getResponse(_, _, _) + EXPECT_CALL(intelligence_mock, getResponse(_, _, _, _) ).WillOnce(Return(res_error)); auto maybe_ans = intell->queryIntelligence(request); @@ -185,7 +185,7 @@ TEST_F(IntelligenceComponentMockTest, getResponseTest) Intelligence::Response response(response_str, 1, false); - EXPECT_CALL(intelligence_mock, getResponse(_, _, _) + EXPECT_CALL(intelligence_mock, getResponse(_, _, _, _) ).WillOnce(Return(response)); auto maybe_ans = intell->queryIntelligence(request); @@ -346,7 +346,7 @@ TEST_F(IntelligenceComponentMockTest, bulkOnlineIntelligenceMockTest) ); Intelligence::Response response(response_str, 4, true); - EXPECT_CALL(intelligence_mock, getResponse(_, _, _, _) + EXPECT_CALL(intelligence_mock, getResponse(_, _, _, _, _) ).WillOnce(Return(response)); auto maybe_ans = intell->queryIntelligence(requests); diff --git a/core/intelligence_is_v2/intelligence_is_v2_ut/intelligence_query_v2_ut.cc b/core/intelligence_is_v2/intelligence_is_v2_ut/intelligence_query_v2_ut.cc index e245a10..c83c427 100644 --- a/core/intelligence_is_v2/intelligence_is_v2_ut/intelligence_query_v2_ut.cc +++ b/core/intelligence_is_v2/intelligence_is_v2_ut/intelligence_query_v2_ut.cc @@ -24,9 +24,33 @@ USE_DEBUG_FLAG(D_INTELLIGENCE); TEST(IntelligenceQueryTestV2, genJsonPrettySingleRequest) { QueryRequest request(Condition::EQUALS, "phase", "testing", true); vector requests = {request}; - Intelligence::IntelligenceRequest query(requests, true, false, MessageMetadata("", 0)); + Intelligence::IntelligenceRequest query(requests, true, false, false, MessageMetadata("", 0)); std::string expected = "{\n" + " \"queryTypes\": {\n" + " \"proxyToCloud\": false\n" + " },\n" + " \"limit\": 20,\n" + " \"fullResponse\": true,\n" + " \"query\": {\n" + " \"operator\": \"equals\",\n" + " \"key\": \"mainAttributes.phase\",\n" + " \"value\": \"testing\"\n" + " }\n" + "}"; + + EXPECT_EQ(*query.genJson(), expected); +} + +TEST(IntelligenceQueryTestV2, genJsonPrettySingleRequestProxied) { + QueryRequest request(Condition::EQUALS, "phase", "testing", true); + vector requests = {request}; + Intelligence::IntelligenceRequest query(requests, true, false, true, MessageMetadata("", 0)); + + std::string expected = "{\n" + " \"queryTypes\": {\n" + " \"proxyToCloud\": true\n" + " },\n" " \"limit\": 20,\n" " \"fullResponse\": true,\n" " \"query\": {\n" @@ -42,9 +66,12 @@ TEST(IntelligenceQueryTestV2, genJsonPrettySingleRequest) { TEST(IntelligenceQueryTestV2, genJsonUnprettySingleRequest) { QueryRequest request(Condition::EQUALS, "phase", "testing", true); vector requests = {request}; - Intelligence::IntelligenceRequest query(requests, false, false, MessageMetadata("", 0)); + Intelligence::IntelligenceRequest query(requests, false, false, false, MessageMetadata("", 0)); std::string expected = "{" + "\"queryTypes\":{" + "\"proxyToCloud\":false" + "}," "\"limit\":20," "\"fullResponse\":true," "\"query\":{" @@ -59,8 +86,11 @@ TEST(IntelligenceQueryTestV2, genJsonUnprettySingleRequest) { TEST(IntelligenceQueryTestV2, genJsonUnprettySingleRequestSpaces) { QueryRequest request(Condition::EQUALS, "ph ase", "te sti\" n g\\", true); vector requests = {request}; - Intelligence::IntelligenceRequest query(requests, false, false, MessageMetadata("", 0)); + Intelligence::IntelligenceRequest query(requests, false, false, false, MessageMetadata("", 0)); std::string expected = "{" + "\"queryTypes\":{" + "\"proxyToCloud\":false" + "}," "\"limit\":20," "\"fullResponse\":true," "\"query\":{" @@ -76,9 +106,53 @@ TEST(IntelligenceQueryTestV2, genJsonPrettyBulkRequests) { QueryRequest request1(Condition::EQUALS, "phase", "testing", true); QueryRequest request2(Condition::EQUALS, "height", "testing", 25); std::vector requests = {request1, request2}; - Intelligence::IntelligenceRequest query(requests, true, true, MessageMetadata("", 0)); + Intelligence::IntelligenceRequest query(requests, true, true, false, MessageMetadata("", 0)); std::string expected = "{\n" + " \"queryTypes\": {\n" + " \"proxyToCloud\": false\n" + " },\n" + " \"queries\": [\n" + " {\n" + " \"query\": {\n" + " \"limit\": 20,\n" + " \"fullResponse\": true,\n" + " \"query\": {\n" + " \"operator\": \"equals\",\n" + " \"key\": \"mainAttributes.phase\",\n" + " \"value\": \"testing\"\n" + " }\n" + " },\n" + " \"index\": 0\n" + " },\n" + " {\n" + " \"query\": {\n" + " \"limit\": 20,\n" + " \"fullResponse\": true,\n" + " \"query\": {\n" + " \"operator\": \"equals\",\n" + " \"key\": \"mainAttributes.height\",\n" + " \"value\": \"testing\"\n" + " }\n" + " },\n" + " \"index\": 1\n" + " }\n" + " ]\n" + "}"; + + EXPECT_EQ(*query.genJson(), expected); +} + +TEST(IntelligenceQueryTestV2, genJsonPrettyBulkRequestsProxied) { + QueryRequest request1(Condition::EQUALS, "phase", "testing", true); + QueryRequest request2(Condition::EQUALS, "height", "testing", 25); + std::vector requests = {request1, request2}; + Intelligence::IntelligenceRequest query(requests, true, true, true, MessageMetadata("", 0)); + + std::string expected = "{\n" + " \"queryTypes\": {\n" + " \"proxyToCloud\": true\n" + " },\n" " \"queries\": [\n" " {\n" " \"query\": {\n" @@ -114,9 +188,12 @@ TEST(IntelligenceQueryTestV2, genJsonUnprettyBulkRequest) { QueryRequest request1(Condition::EQUALS, "phase", "testing", true); QueryRequest request2(Condition::EQUALS, "height", "testing", 25); std::vector requests = {request1, request2}; - Intelligence::IntelligenceRequest query(requests, false, true, MessageMetadata("", 0)); + Intelligence::IntelligenceRequest query(requests, false, true, false, MessageMetadata("", 0)); std::string expected = "{" + "\"queryTypes\":{" + "\"proxyToCloud\":false" + "}," "\"queries\":[{" "\"query\":{" "\"limit\":20," diff --git a/core/intelligence_is_v2/intelligence_is_v2_ut/query_request_v2_ut.cc b/core/intelligence_is_v2/intelligence_is_v2_ut/query_request_v2_ut.cc index 95e097a..8b781f4 100644 --- a/core/intelligence_is_v2/intelligence_is_v2_ut/query_request_v2_ut.cc +++ b/core/intelligence_is_v2/intelligence_is_v2_ut/query_request_v2_ut.cc @@ -705,3 +705,59 @@ TEST(QueryRequestTestV2, UninitializedObjectTypeTest) EXPECT_THAT(debug_output.str(), HasSubstr(debug_str)); Debug::setNewDefaultStdout(&cout); } + +TEST(QueryRequestTestV2, Bug40968) +{ + QueryRequest request(Intelligence_IS_V2::Condition::EQUALS, "field1", "123", false); + QueryRequest filter1(Intelligence_IS_V2::Condition::EQUALS, "field2", "123", false); + request = request || filter1; + + QueryRequest filter2(Intelligence_IS_V2::Condition::NOT_EQUALS, "field3", "123", false); + request = request && filter2; + + QueryRequest filter3(Intelligence_IS_V2::Condition::EQUALS, "field3", "234", false); + request = request && filter3; + + stringstream out2; + { + cereal::JSONOutputArchive out_ar2(out2); + request.saveToJson(out_ar2); + } + string req = + "{\n" + " \"limit\": 20,\n" + " \"fullResponse\": false,\n" + " \"query\": {\n" + " \"operator\": \"and\",\n" + " \"operands\": [\n" + " {\n" + " \"operator\": \"or\",\n" + " \"operands\": [\n" + " {\n" + " \"operator\": \"equals\",\n" + " \"key\": \"mainAttributes.field1\",\n" + " \"value\": \"123\"\n" + " },\n" + " {\n" + " \"operator\": \"equals\",\n" + " \"key\": \"mainAttributes.field2\",\n" + " \"value\": \"123\"\n" + " }\n" + " ]\n" + " },\n" + " {\n" + " \"operator\": \"notEquals\",\n" + " \"key\": \"mainAttributes.field3\",\n" + " \"value\": \"123\"\n" + " },\n" + " {\n" + " \"operator\": \"equals\",\n" + " \"key\": \"mainAttributes.field3\",\n" + " \"value\": \"234\"\n" + " }\n" + " ]\n" + " }\n" + "}"; + + EXPECT_EQ(out2.str(), req); +} diff --git a/core/intelligence_is_v2/intelligence_request.cc b/core/intelligence_is_v2/intelligence_request.cc index c6ca113..50f767e 100644 --- a/core/intelligence_is_v2/intelligence_request.cc +++ b/core/intelligence_is_v2/intelligence_request.cc @@ -89,6 +89,12 @@ IntelligenceRequest::genJson() const JsonStream json_stream(&str_stream, is_pretty); { cereal::JSONOutputArchive out_ar(json_stream); + + out_ar.setNextName("queryTypes"); + out_ar.startNode(); + out_ar(cereal::make_nvp("proxyToCloud", is_proxy)); + out_ar.finishNode(); + if (isBulk()) { out_ar.setNextName("queries"); out_ar.startNode(); diff --git a/core/intelligence_is_v2/query_filter_v2.cc b/core/intelligence_is_v2/query_filter_v2.cc index 6c8dd7a..ee014b4 100644 --- a/core/intelligence_is_v2/query_filter_v2.cc +++ b/core/intelligence_is_v2/query_filter_v2.cc @@ -65,6 +65,11 @@ SerializableQueryFilter::SerializableQueryFilter( condition_operands.emplace_back(condition_type, key, value); } +SerializableQueryFilter::SerializableQueryFilter(const SerializableQueryCondition &condition) +{ + condition_operands.push_back(condition); +} + SerializableQueryFilter::SerializableQueryFilter( Condition condition_type, @@ -159,31 +164,38 @@ SerializableQueryFilter::calcOperator(const SerializableQueryFilter &other_query query_filter_res.operator_type = oper; - if (isOperatorComp(oper) && other_query.isOperatorComp(oper)) { - size_t queries_size = queries_operands.size() + other_query.queries_operands.size(); - size_t conditions_size = condition_operands.size() + other_query.condition_operands.size(); - query_filter_res.queries_operands.reserve(queries_size); - query_filter_res.condition_operands.reserve(conditions_size); - - for (const auto &subquery : queries_operands) { - query_filter_res.queries_operands.push_back(subquery); - } - - for (const auto &condition : condition_operands) { - query_filter_res.condition_operands.push_back(condition); - } - - for (const auto &subquery : other_query.queries_operands) { - query_filter_res.queries_operands.push_back(subquery); - } - - for (const auto &condition : other_query.condition_operands) { - query_filter_res.condition_operands.push_back(condition); - } - } else { + if (!isOperatorComp(oper) || !other_query.isOperatorComp(oper)) { query_filter_res.queries_operands.reserve(2); query_filter_res.queries_operands.push_back(*this); query_filter_res.queries_operands.push_back(other_query); + return query_filter_res; + } + + if (!condition_operands.empty() && !other_query.condition_operands.empty()) { + query_filter_res.condition_operands.reserve(queries_operands.size() + other_query.queries_operands.size()); + for (const auto &condition : condition_operands) { + query_filter_res.condition_operands.push_back(condition); + } + for (const auto &condition : other_query.condition_operands) { + query_filter_res.condition_operands.push_back(condition); + } + return query_filter_res; + } + + size_t queries_size = queries_operands.size() + other_query.queries_operands.size(); + size_t conditions_size = condition_operands.size() + other_query.condition_operands.size(); + query_filter_res.queries_operands.reserve(queries_size + conditions_size); + for (const auto &subquery : queries_operands) { + query_filter_res.queries_operands.push_back(subquery); + } + for (const auto &condition : condition_operands) { + query_filter_res.queries_operands.emplace_back(condition); + } + for (const auto &subquery : other_query.queries_operands) { + query_filter_res.queries_operands.push_back(subquery); + } + for (const auto &condition : other_query.condition_operands) { + query_filter_res.queries_operands.emplace_back(condition); } return query_filter_res; diff --git a/core/messaging/messaging_comp/messaging_comp.cc b/core/messaging/messaging_comp/messaging_comp.cc index 4aaf040..e48a8c7 100644 --- a/core/messaging/messaging_comp/messaging_comp.cc +++ b/core/messaging/messaging_comp/messaging_comp.cc @@ -18,6 +18,7 @@ #include "agent_core_utilities.h" #include "connection_comp.h" +#include "rest.h" #include "debug.h" #include "messaging_buffer.h" @@ -25,6 +26,40 @@ using namespace std; USE_DEBUG_FLAG(D_MESSAGING); +class FogConnectionChecker : public ServerRest +{ +public: + void + doCall() override + { + dbgTrace(D_MESSAGING) << "Checking connection to the FOG"; + auto response = Singleton::Consume::from()->sendSyncMessage( + HTTPMethod::GET, + "/access-manager/health/live", + string("") + ); + if (!response.ok()) { + dbgTrace(D_MESSAGING) << "Failed to check connection to the FOG"; + connected_to_fog = false; + error = response.getErr().toString(); + return; + } + if (response.unpack().getHTTPStatusCode() == HTTPStatusCode::HTTP_OK) { + dbgTrace(D_MESSAGING) << "Connected to the FOG"; + connected_to_fog = true; + error = ""; + } else { + dbgTrace(D_MESSAGING) << "No connection to the FOG"; + connected_to_fog = false; + error = response.unpack().toString(); + } + } + +private: + S2C_PARAM(bool, connected_to_fog); + S2C_PARAM(string, error); +}; + void MessagingComp::init() { @@ -42,6 +77,13 @@ MessagingComp::init() "message", "Buffer Failed Requests" ); + + if (Singleton::exists()) { + Singleton::Consume::by()->addRestCall( + RestAction::SHOW, + "check-fog-connection" + ); + } } static bool diff --git a/core/messaging/messaging_comp/messaging_comp_ut/messaging_comp_ut.cc b/core/messaging/messaging_comp/messaging_comp_ut/messaging_comp_ut.cc index 84c8ea2..ed2cc94 100644 --- a/core/messaging/messaging_comp/messaging_comp_ut/messaging_comp_ut.cc +++ b/core/messaging/messaging_comp/messaging_comp_ut/messaging_comp_ut.cc @@ -15,6 +15,8 @@ #include "mocks/mock_messaging_connection.h" #include "rest.h" #include "rest_server.h" +#include "mock/mock_messaging.h" +#include "mock/mock_rest_api.h" #include "dummy_socket.h" using namespace std; @@ -26,12 +28,6 @@ operator<<(ostream &os, const Maybe &) return os; } -static std::ostream & -operator<<(std::ostream &os, const HTTPResponse &) -{ - return os; -} - static std::ostream & operator<<(std::ostream &os, const HTTPStatusCode &) { @@ -51,6 +47,9 @@ public: { Debug::setUnitTestFlag(D_MESSAGING, Debug::DebugLevel::TRACE); EXPECT_CALL(mock_time_get, getMonotonicTime()).WillRepeatedly(Return(chrono::microseconds(0))); + EXPECT_CALL(mock_rest, mockRestCall(RestAction::SHOW, "check-fog-connection", _)) + .WillOnce(WithArg<2>(Invoke(this, &TestMessagingComp::showFogConnection)) + ); ON_CALL(mock_agent_details, getFogDomain()).WillByDefault(Return(Maybe(fog_addr))); ON_CALL(mock_agent_details, getFogPort()).WillByDefault(Return(Maybe(fog_port))); @@ -73,6 +72,13 @@ public: EXPECT_CALL(mock_proxy_conf, getProxyAuthentication(_)).WillRepeatedly(Return(string("cred"))); } + bool + showFogConnection(const unique_ptr &p) + { + show_fog_connection = p->getRest(); + return true; + } + const string fog_addr = "127.0.0.1"; int fog_port = 8080; CPTestTempfile agent_details_file; @@ -85,16 +91,37 @@ public: NiceMock mock_time_get; NiceMock mock_agent_details; NiceMock mock_proxy_conf; + NiceMock mock_rest; + NiceMock mock_message; + unique_ptr show_fog_connection; DummySocket dummy_socket; }; -TEST_F(TestMessagingComp, testInitComp) +TEST_F(TestMessagingComp, testCheckFogConnectivity) { - EXPECT_CALL( - mock_mainloop, addRecurringRoutine(I_MainLoop::RoutineType::Timer, _, _, "Delete expired cache entries", _) - ) - .WillOnce(Return(0)); - messaging_comp.init(); + setAgentDetails(); + HTTPResponse res( + HTTPStatusCode::HTTP_OK, + string( + "{" + " \"up\": true," + " \"timestamp\":\"\"" + "}" + ) + ); + + EXPECT_CALL(mock_message, sendSyncMessage(HTTPMethod::GET, "/access-manager/health/live", "", _, _)) + .WillOnce(Return(res)); + + stringstream ss("{}"); + Maybe maybe_res = show_fog_connection->performRestCall(ss); + EXPECT_TRUE(maybe_res.ok()); + EXPECT_EQ(maybe_res.unpack(), + "{\n" + " \"connected_to_fog\": true,\n" + " \"error\": \"\"\n" + "}" + ); } TEST_F(TestMessagingComp, testSendSyncMessage) diff --git a/core/report/tag_and_enum_management.cc b/core/report/tag_and_enum_management.cc index 80f0f3a..824d5e3 100644 --- a/core/report/tag_and_enum_management.cc +++ b/core/report/tag_and_enum_management.cc @@ -111,7 +111,9 @@ TagAndEnumManagement::convertStringToTag(const string &tag) {"Playground", ReportIS::Tags::PLAYGROUND}, {"Nginx Proxy Manager", ReportIS::Tags::NGINX_PROXY_MANAGER}, {"APISIX Server", ReportIS::Tags::WEB_SERVER_APISIX}, - {"Docker Deployment", ReportIS::Tags::DEPLOYMENT_DOCKER} + {"Docker Deployment", ReportIS::Tags::DEPLOYMENT_DOCKER}, + {"SWAG Server", ReportIS::Tags::WEB_SERVER_SWAG}, + {"NGINX Unified Server", ReportIS::Tags::WEB_SERVER_NGINX_UNIFIED} }; auto report_is_tag = strings_to_tags.find(tag); @@ -320,7 +322,9 @@ EnumArray TagAndEnumManagement::tags_translation_arr { "apiDiscoveryCloudMessaging", "Nginx Proxy Manager", "APISIX Server", - "Docker Deployment" + "Docker Deployment", + "SWAG Server", + "NGINX Unified Server" }; EnumArray TagAndEnumManagement::audience_team_translation { diff --git a/core/version/CMakeLists.txt b/core/version/CMakeLists.txt index 32e8a80..b99bdfd 100644 --- a/core/version/CMakeLists.txt +++ b/core/version/CMakeLists.txt @@ -2,7 +2,7 @@ set(VERSION_VARS_H_FILE ${CMAKE_CURRENT_BINARY_DIR}/version_vars.h) set(BUILD_SCRIPT build_version_vars_h.py) add_custom_command( OUTPUT ${VERSION_VARS_H_FILE} - COMMAND CI_PIPELINE_ID=00000001 CI_BUILD_REF_NAME=open-source python3 ${BUILD_SCRIPT} "userspace" > ${VERSION_VARS_H_FILE} + COMMAND CI_PIPELINE_ID=00000001 CI_COMMIT_REF_NAME=open-source python3 ${BUILD_SCRIPT} "userspace" > ${VERSION_VARS_H_FILE} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${BUILD_SCRIPT} ) diff --git a/core/version/build_version_vars_h.py b/core/version/build_version_vars_h.py index 53f6e05..9f99fbb 100755 --- a/core/version/build_version_vars_h.py +++ b/core/version/build_version_vars_h.py @@ -15,7 +15,7 @@ timestamp = "%s%s" % (now.replace(microsecond=0).isoformat(), time.strftime("%z" version_prefix = "" full_version = "private" -branch = os.getenv("CI_BUILD_REF_NAME") +branch = os.getenv("CI_COMMIT_REF_NAME") if branch is None: branch = "private" diff --git a/nodes/orchestration/CMakeLists.txt b/nodes/orchestration/CMakeLists.txt index a6af870..2b1bdd7 100755 --- a/nodes/orchestration/CMakeLists.txt +++ b/nodes/orchestration/CMakeLists.txt @@ -18,6 +18,7 @@ target_link_libraries( orchestration health_check health_check_manager + updates_process_reporter service_controller manifest_controller package_handler diff --git a/nodes/orchestration/package/local-default-policy.yaml b/nodes/orchestration/package/local-default-policy.yaml index e963ebf..efc0223 100644 --- a/nodes/orchestration/package/local-default-policy.yaml +++ b/nodes/orchestration/package/local-default-policy.yaml @@ -52,7 +52,7 @@ log-triggers: url-path: false url-query: false log-destination: - cloud: true + cloud: false stdout: format: json diff --git a/nodes/orchestration/package/open-appsec-ctl.sh b/nodes/orchestration/package/open-appsec-ctl.sh index 326cdcc..a867216 100644 --- a/nodes/orchestration/package/open-appsec-ctl.sh +++ b/nodes/orchestration/package/open-appsec-ctl.sh @@ -13,7 +13,6 @@ DEFAULT_PORT_INDEX=2 DISPLAY_NAME_INDEX=3 SERVICE_PORTS_LIST_INDEX=4 -PACKAGE_LIST_LINE_OFFSET=5 cp_nano_conf_location="conf" @@ -150,17 +149,21 @@ fi all_services="" -lines_to_skip=$((PACKAGE_LIST_LINE_OFFSET)) -{ - while [ $lines_to_skip -ne 0 ]; do - read -r line - lines_to_skip=$((lines_to_skip - 1)) - done - while read -r line; do - service_name="$(echo "$line" | cut -d "=" -f1 | tr "_" "-")" - all_services="${all_services} $service_name" - done -} <"${FILESYSTEM_PATH}/${CP_SCRIPTS_PATH}/${CP_NANO_PACKAGE_LIST_NAME}" +while IFS= read -r line; do + # Skip empty lines and lines that start with # + if [ -z "$(echo "${line}" | tr -d '[:space:]')" ]; then + continue + fi + if [ "${line#"#"}" != "$line" ]; then + continue + fi + + service_name=$(echo "$line" | cut -d "=" -f1 | tr "_" "-") + # Check if the service name already exists in the list + if ! echo "$all_services" | grep -q "\<$service_name\>"; then + all_services="$all_services $service_name" + fi +done <"${FILESYSTEM_PATH}/${CP_SCRIPTS_PATH}/${CP_NANO_PACKAGE_LIST_NAME}" is_valid_var_name() # Initials - ivvn { @@ -392,7 +395,7 @@ extract_default_api_port() # Initials - edap is_requested_service() # Initials - irs { irs_requested_service=$(echo "$1" | sed 's/-//g' | tr '[:upper:]' '[:lower:]') - irs_possible_service=$(echo "$2" | sed 's/-//g' | tr '[:upper:]' '[:lower:]') + irs_possible_service=$(echo "$2" | sed 's/^cp-nano-//' | sed 's/-//g' | tr '[:upper:]' '[:lower:]') if [ "$irs_requested_service" = "$irs_possible_service" ]; then echo true return @@ -409,10 +412,10 @@ extract_api_port() # Initials - eap return fi - for pair in $(get_registered_services_ports | tr "," " "); do + for pair in $(get_registered_services_ports | tr ";" " "); do eap_service="$(echo "$pair" | cut -d ':' -f1)" if [ "$(is_requested_service "$eap_service_name" "$eap_service")" = true ]; then - echo "$pair" | cut -d ':' -f2 + echo "$pair" | cut -d ':' -f2 | tr "," " " return fi done @@ -638,7 +641,9 @@ run_update_gradual_policy() # Initials - rugp rugp_service_api_port=$(extract_api_port "$rugp_service_name") # Load gradual policy configuration - rugp_errors=$(curl_func "${rugp_service_api_port}" "set-gradual-deployment-policy" "${rugp_data}") + for port in $rugp_service_api_port; do + rugp_errors=$(curl_func "$port" "set-gradual-deployment-policy" "${rugp_data}") + done sleep 1 if [ -n "$(echo "$rugp_errors" | sed "s/$(printf '\r')//g")" ]; then echo "Failed to set gradual policy. Error: $rugp_errors" @@ -674,11 +679,9 @@ run_set_traffic_recording_policy() # Initials - rstrp # Send signal to http_manager to update the traffic recording policy rstrp_data='{"traffic_recording_flags":["'$1'"]}' - if [ "${remove_curl_ld_path}" = "true" ]; then - LD_LIBRARY_PATH="" ${curl_cmd} --noproxy "*" --header "Content-Type: application/json" --request POST --data "$rstrp_data" http://127.0.0.1:"$(extract_api_port 'http-manager')"/set-traffic-recording-policy - else - ${curl_cmd} --noproxy "*" --header "Content-Type: application/json" --request POST --data "$rstrp_data" http://127.0.0.1:"$(extract_api_port 'http-manager')"/set-traffic-recording-policy - fi + for port in $(extract_api_port 'http-manager'); do + curl_func "$port" "set-traffic-recording-policy" "${rugp_data}" + done sleep 1 } @@ -809,16 +812,20 @@ run_print_metrics() # Initials - rpm if [ -z "$rpm_service_name" ]; then print_metrics "Orchestration" - rpm_list=$(get_registered_services_ports | tr "," " ") + rpm_list=$(get_registered_services_ports | tr ";" " ") for pair in ${rpm_list}; do rpm_service=$(echo "$pair" | cut -d ':' -f1) - print_metrics "$rpm_service" "$(echo "$pair" | cut -d ':' -f2)" + rpm_port=$(echo "$pair" | cut -d ':' -f2) + for port in $(echo $rpm_port | tr "," " "); do + print_metrics "$rpm_service" "$port" + done done elif [ "$rpm_service_name" = "orchestration" ]; then print_metrics "Orchestration" else - rpm_port=$(extract_api_port "$rpm_service_name") - print_metrics "$rpm_service_name" "$rpm_port" + for port in $(extract_api_port "$rpm_service_name"); do + print_metrics "$rpm_service_name" "$port" + done fi } @@ -886,7 +893,7 @@ print_single_service_status() # Initials - psss psss_is_userspace_process_running=$(is_userspace_running "$psss_service_name") psss_maybe_version=$(LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$USR_LIB_PATH/cpnano"$LD_LIBRARY_PATH_ADD" $psss_service_full_path --version 2>&1) - if echo "$psss_maybe_version" | grep -q "error"; then + if echo "$psss_maybe_version" | grep -iq "error"; then echo "Version: Temporarily unavailable" format_colored_status_line "Status: Not Available" echo "" @@ -1008,7 +1015,8 @@ run_status() # Initials - rs fi fi - if [ -n "$(cat ${FILESYSTEM_PATH}/conf/agent_details.json | grep "hybrid_mode")" ]; then + hybrid_mode=$(cat ${FILESYSTEM_PATH}/conf/agent_details.json | grep "hybrid_mode") + if [ -n "$hybrid_mode" ]; then add_policy_file=true rs_mgmt_mode_text="Local management" else @@ -1019,8 +1027,16 @@ run_status() # Initials - rs add_policy_file=true rs_mgmt_mode_text="Cloud management (Visibility mode)" fi + rs_profile_id=$(cat ${FILESYSTEM_PATH}/$cp_nano_conf_location/agent_details.json | grep "Profile ID" | cut -d '"' -f4) fi + + rs_agent_id=$(cat ${FILESYSTEM_PATH}/$cp_nano_conf_location/agent_details.json | grep "Agent ID" | cut -d '"' -f4) + echo "Management mode: ${rs_mgmt_mode_text}" + echo "Agent ID: ${rs_agent_id}" + if [ -z "$hybrid_mode" ]; then + echo "Profile ID: ${rs_profile_id}" + fi if [ "${add_policy_file}" = "true" ]; then echo "Policy files: " @@ -1189,6 +1205,7 @@ run_cpnano_debug() # Initials - rcd { CP_ENV_FILESYSTEM=${FILESYSTEM_PATH} CP_ENV_LOG_FILE=${LOG_FILE_PATH} ${FILESYSTEM_PATH}/${CP_SCRIPTS_PATH}/${CP_NANO_DEBUG_NAME} "${@}" rcd_script_exit_code=$? + rcd_set_config_res= # exit code of -1 from the script becomes 255 here if [ $rcd_script_exit_code -eq 0 ]; then exit 0 @@ -1212,7 +1229,20 @@ run_cpnano_debug() # Initials - rcd if [ "$rcd_load_all_settings" = "true" ]; then for service in $all_services; do if [ "$(is_userspace_running "${service}")" = "true" ]; then - run_load_settings "$service" + if [ "$service" = "orchestration" ]; then + rcd_set_config_res=$(curl_to_orchestration "set-change-debug-config") + else + for port in $(extract_api_port "$service"); do + rcd_set_config_res=$(curl_func $port "set-change-debug-config") + done + fi + rcd_service_formatted=$(format_nano_service_name "$service") + if echo "$rcd_set_config_res" | grep -q "Error"; then + echo "Failed to load debug configuration for $rcd_service_formatted service." + echo "$rcd_set_config_res" + else + echo "$rcd_service_formatted debug configuration updated successfully" + fi fi done @@ -1223,7 +1253,20 @@ run_cpnano_debug() # Initials - rcd if [ -z "$1" ]; then return elif [ -n "$(get_nano_service_location_and_port "$1")" ]; then - run_load_settings "$1" + if [ "$1" = "orchestration" ]; then + rcd_set_config_res=$(curl_to_orchestration "set-change-debug-config") + else + for port in $(extract_api_port "$1"); do + rcd_set_config_res=$(curl_func $port "set-change-debug-config") + done + fi + rcd_service_formatted=$(format_nano_service_name "$1") + if echo "$rcd_set_config_res" | grep -q "Error"; then + echo "Failed to load debug configuration for $rcd_service_formatted service." + echo "$rcd_set_config_res" + else + echo "$rcd_service_formatted debug configuration updated successfully" + fi fi shift done diff --git a/nodes/orchestration/package/orchestration_package.sh b/nodes/orchestration/package/orchestration_package.sh index abecd7f..85fdf1d 100755 --- a/nodes/orchestration/package/orchestration_package.sh +++ b/nodes/orchestration/package/orchestration_package.sh @@ -418,9 +418,9 @@ cp_print() printf "%b\n" "$1" fi if [ "$is_smb" != "1" ]; then - printf "%b\n" "$1" >> ${LOG_FILE_PATH}/${LOG_PATH}/${INSTALLATION_LOG_FILE} + printf "[%s] %b\n" "$(date +%Y-%m-%dT%H:%M:%S)" "$1" >> ${LOG_FILE_PATH}/${LOG_PATH}/${INSTALLATION_LOG_FILE} else - printf "%b\n" "$1" >> ${SMB_LOG_FILE_PATH}/${LOG_PATH}/${INSTALLATION_LOG_FILE} + printf "[%s] %b\n" "$(date +%Y-%m-%dT%H:%M:%S)" "$1" >> ${SMB_LOG_FILE_PATH}/${LOG_PATH}/${INSTALLATION_LOG_FILE} fi } @@ -897,7 +897,7 @@ uninstall_messaging_proxy_if_needed() get_status_content() { - gsc_temp_old_status=$(sed -e 's/{\|}\|,\|"//g' -e '/^\s*$/d' -e 's/^ //' ${FILESYSTEM_PATH}/conf/orchestration_status.json) + gsc_temp_old_status=$(sed -e 's/{\|}\|,\|"//g' -e '/^\s*$/d' -e 's/^ //' ${FILESYSTEM_PATH}/conf/orchestration_status.json 2>1) echo ${gsc_temp_old_status} } @@ -956,9 +956,16 @@ install_orchestration() add_uninstall_script cp_exec "cp -f certificate/ngen.body.crt ${FILESYSTEM_PATH}/${CERTS_PATH}/fog.pem" - if [ -n ${OTP_TOKEN} ]; then + if [ -n "${OTP_TOKEN}" ]; then cp_print "Saving authentication token to file" printf '{\n "registration type": "token",\n "registration data": "%b"\n}' "$OTP_TOKEN" | ${FILESYSTEM_PATH}/${BIN_PATH}/${CP_NANO_BASE64} -e > ${FILESYSTEM_PATH}/${CONF_PATH}/registration-data.json + rm ${FILESYSTEM_PATH}/${CONF_PATH}/agent_details.json + rm ${FILESYSTEM_PATH}/${CONF_PATH}/orchestration_status.json + echo '{}'>${FILESYSTEM_PATH}/${CONF_PATH}/policy.json + + if [ -f ${FILESYSTEM_PATH}/data/data5.a ]; then + rm ${FILESYSTEM_PATH}/data/data5.a + fi fi [ -f "${FILESYSTEM_PATH}/${SERVICE_PATH}/${ORCHESTRATION_FILE_NAME}.cfg" ] && . "${FILESYSTEM_PATH}/${SERVICE_PATH}/${ORCHESTRATION_FILE_NAME}.cfg"