First release of open-appsec source code

This commit is contained in:
roybarda
2022-10-26 19:33:19 +03:00
parent 3883109caf
commit a883352f79
1353 changed files with 276290 additions and 1 deletions

View File

@@ -0,0 +1,3 @@
add_library(manifest_controller manifest_controller.cc manifest_diff_calculator.cc manifest_handler.cc)
add_subdirectory(manifest_controller_ut)

View File

@@ -0,0 +1,445 @@
// 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 "manifest_controller.h"
#include "config.h"
#include "debug.h"
#include "sasal.h"
#include "environment.h"
#include "version.h"
#include "log_generator.h"
#include "orchestration_comp.h"
using namespace std;
using namespace ReportIS;
SASAL_START // Orchestration - Manifest Handler
USE_DEBUG_FLAG(D_ORCHESTRATOR);
class IgnoredPackages
{
public:
void
load(istream &input, char delim)
{
string ignored_package;
while (getline(input, ignored_package, delim))
{
if (ignored_package == "all") {
ignore_packages.clear();
ignore_packages.insert(ignored_package);
dbgInfo(D_ORCHESTRATOR) << "Will ignore updates for all packages";
break;
} else if (ignored_package == "none") {
ignore_packages.clear();
dbgInfo(D_ORCHESTRATOR) << "Will not ignore updates of any packages";
break;
}
if (ignored_package.size() > 0) {
ignore_packages.insert(ignored_package);
dbgInfo(D_ORCHESTRATOR) << "Updates for package " << ignored_package << " will be ignored";
}
}
}
void
load(const string &raw_value)
{
string token;
istringstream tokenStream(raw_value);
load(tokenStream, ',');
}
const set<string> & operator*() const { return ignore_packages; }
private:
set<string> ignore_packages;
};
class ManifestController::Impl : Singleton::Provide<I_ManifestController>::From<ManifestController>
{
public:
void init();
bool updateManifest(const string &new_manifest_file) override;
bool loadAfterSelfUpdate() override;
private:
bool changeManifestFile(const string &new_manifest_file);
bool
handlePackage(
const Package &updated_package,
map<string, Package> &current_packages,
const map<string, Package> &new_packages,
map<string, Package> &corrupted_packages
);
ManifestDiffCalculator manifest_diff_calc;
ManifestHandler manifest_handler;
string manifest_file_path;
string corrupted_file_list;
string temp_ext;
string backup_ext;
string packages_dir;
string orch_service_name;
set<string> ignore_packages;
};
void
ManifestController::Impl::init()
{
manifest_diff_calc.init();
manifest_handler.init();
dbgTrace(D_ORCHESTRATOR) << "Manifest controller, file system path prefix: " << getFilesystemPathConfig();
manifest_file_path = getConfigurationWithDefault<string>(
getFilesystemPathConfig() + "/conf/manifest.json",
"orchestration",
"Manifest file path"
);
corrupted_file_list = getConfigurationWithDefault<string>(
getFilesystemPathConfig() + "/conf/corrupted_packages.json",
"orchestration",
"Manifest corrupted files path"
);
temp_ext = getConfigurationWithDefault<string>("_temp", "orchestration", "Temp file extension");
backup_ext = getConfigurationWithDefault<string>(".bk", "orchestration", "Backup file extension");
packages_dir = getConfigurationWithDefault<string>(
getFilesystemPathConfig() + "/packages",
"orchestration",
"Packages directory"
);
orch_service_name = getConfigurationWithDefault<string>("orchestration", "orchestration", "Service name");
auto ignore_packages_path = getConfigurationWithDefault<string>(
getFilesystemPathConfig() + "/conf/ignore-packages.txt",
"orchestration",
"Ignore packages list file path"
);
if (Singleton::Consume<I_OrchestrationTools>::by<ManifestController>()->doesFileExist(ignore_packages_path)) {
try {
ifstream input_stream(ignore_packages_path);
if (!input_stream) {
dbgWarning(D_ORCHESTRATOR)
<< "Cannot open the file with ignored packages. "
<< "File: " << ignore_packages_path;
} else {
IgnoredPackages packages_to_ignore;
packages_to_ignore.load(input_stream, '\n');
ignore_packages = *packages_to_ignore;
input_stream.close();
}
} catch (ifstream::failure &f) {
dbgWarning(D_ORCHESTRATOR)
<< "Cannot read the file with ignored packages."
<< " File: " << ignore_packages_path
<< " Error: " << f.what();
}
}
}
bool
ManifestController::Impl::updateManifest(const string &new_manifest_file)
{
auto i_env = Singleton::Consume<I_Environment>::by<ManifestController>();
auto span_scope = i_env->startNewSpanScope(Span::ContextType::CHILD_OF);
dbgDebug(D_ORCHESTRATOR) << "Starting to update manifest file";
auto ignored_settings_packages = getProfileAgentSetting<IgnoredPackages>("orchestration.IgnoredPackagesList");
set<string> packages_to_ignore = ignore_packages;
if (ignored_settings_packages.ok()) packages_to_ignore = *(*ignored_settings_packages);
auto orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<ManifestController>();
if (packages_to_ignore.count("all") > 0) {
dbgTrace(D_ORCHESTRATOR) << "Nothing to update (\"ignore all\" turned on)";
if (!orchestration_tools->copyFile(new_manifest_file, manifest_file_path)) {
dbgWarning(D_ORCHESTRATOR) << "Failed to copy a new manifest file";
return false;
}
return true;
}
Maybe<map<string, Package>> parsed_manifest = orchestration_tools->loadPackagesFromJson(new_manifest_file);
if (!parsed_manifest.ok()) {
dbgWarning(D_ORCHESTRATOR) << "Failed to parse the new manifest file. File: " << new_manifest_file;
return false;
}
map<string, Package> new_packages = parsed_manifest.unpack();
map<string, Package> current_packages;
parsed_manifest = orchestration_tools->loadPackagesFromJson(manifest_file_path);
if (!parsed_manifest.ok()){
dbgWarning(D_ORCHESTRATOR) << "Can not parse the current manifest file, start with new one.";
} else {
current_packages = parsed_manifest.unpack();
}
// Remove any update of all ignore packages
for (const auto &ignore_package : packages_to_ignore) {
dbgInfo(D_ORCHESTRATOR) << "Ignoring a package from the manifest. Package name: " << ignore_package;
if (new_packages.count(ignore_package) > 0) {
// Get the change as-is of the ignore package - it won"t update the service
current_packages[ignore_package] = new_packages[ignore_package];
} else {
// Remove the ignore package from the current manifest file - it won't uninstall the service
current_packages.erase(ignore_package);
}
}
map<string, Package> corrupted_packages;
parsed_manifest = orchestration_tools->loadPackagesFromJson(corrupted_file_list);
if (!parsed_manifest.ok()){
dbgWarning(D_ORCHESTRATOR) << "Can not parse corrupted services file, start with new one.";
} else {
corrupted_packages = parsed_manifest.unpack();
}
bool all_cleaned = true;
bool uninstall_done = false;
// Removes all the untracked packages. new_packages will be cleaned from already installed packages
auto packages_to_remove = manifest_diff_calc.filterUntrackedPackages(current_packages, new_packages);
for (auto remove_package = packages_to_remove.begin(); remove_package != packages_to_remove.end();) {
bool uninstall_response = true;
if (remove_package->second.isInstallable().ok()) {
uninstall_response = manifest_handler.uninstallPackage(remove_package->second);
}
if (!uninstall_response) {
dbgWarning(D_ORCHESTRATOR)
<< "Failed to uninstall package. Package: " << remove_package->second.getName();
all_cleaned = false;
remove_package++;
} else {
uninstall_done = true;
current_packages.erase(remove_package->first);
remove_package = packages_to_remove.erase(remove_package);
}
}
if (uninstall_done) {
if (!orchestration_tools->packagesToJsonFile(current_packages, manifest_file_path)) {
dbgWarning(D_ORCHESTRATOR) << "Failed to update manifest file. File: "
<< manifest_file_path;
} else {
dbgInfo(D_ORCHESTRATOR) << "Manifest file was updated successfully. File: "
<< manifest_file_path;
}
}
bool no_change = new_packages.size() == 0;
// Both new_packages & corrupted_packages will be updated based on updated manifest
bool no_corrupted_package = manifest_diff_calc.filterCorruptedPackages(new_packages, corrupted_packages);
auto orchestration_service = new_packages.find("orchestration");
if (orchestration_service != new_packages.end()) {
// Orchestration needs special handling as manifest should be backup differently
return handlePackage(
orchestration_service->second,
current_packages,
new_packages,
corrupted_packages
);
}
auto wlp_standalone_service = new_packages.find("wlpStandalone");
if (wlp_standalone_service != new_packages.end()) {
// wlpStandalone needs special handling as manifest should be backup differently
return handlePackage(
wlp_standalone_service->second,
current_packages,
new_packages,
corrupted_packages
);
}
bool all_installed = true;
bool any_installed = false;
dbgDebug(D_ORCHESTRATOR) << "Starting to handle " << new_packages.size() <<" new packages";
for (auto &new_package : new_packages) {
if (new_package.second.getType() != Package::PackageType::Service) continue;
size_t prev_size = corrupted_packages.size();
bool handling_response = handlePackage(
new_package.second,
current_packages,
new_packages,
corrupted_packages
);
// During handlePackage function, package installation might fail so it will be added to
// corrupted_packages. Corrupted file needs to be updated accordingly
if (prev_size < corrupted_packages.size() &&
!orchestration_tools->packagesToJsonFile(corrupted_packages, corrupted_file_list)) {
dbgWarning(D_ORCHESTRATOR) << "Failed to update corrupted packages list.";
}
// Orchestration needs special handling as manifest should be backup differently
if (new_package.first.compare(orch_service_name) == 0) {
return handling_response;
}
any_installed = any_installed || handling_response;
all_installed = all_installed && handling_response;
}
bool manifest_file_update = true;
if (all_installed && (any_installed || no_change) && no_corrupted_package) {
manifest_file_update = changeManifestFile(new_manifest_file);
} else if (any_installed) {
manifest_file_update = orchestration_tools->packagesToJsonFile(current_packages, manifest_file_path);
}
return all_installed && manifest_file_update && no_corrupted_package && all_cleaned;
}
// Orchestration package needs a special handling. Old service will die during the upgrade
// so we need to keep temporary manifest file to prevent overwriting. Once Orchestration upgrade
// finish, we return to regular path.
bool
ManifestController::Impl::loadAfterSelfUpdate()
{
dbgDebug(D_ORCHESTRATOR) << "Starting load after the self update function";
string temp_manifest_path = manifest_file_path + temp_ext;
auto orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<ManifestController>();
if (!orchestration_tools->doesFileExist(temp_manifest_path)) {
return true;
}
dbgDebug(D_ORCHESTRATOR) << "Orchestration updated itself";
// Run post installation test
auto package_handler = Singleton::Consume<I_PackageHandler>::by<ManifestController>();
string current_file = packages_dir + "/" + orch_service_name + "/" + orch_service_name;
if (!package_handler->postInstallPackage(orch_service_name, current_file + temp_ext)) {
dbgWarning(D_ORCHESTRATOR) << "Failed in post install test. Package: " << orch_service_name;
return false;
}
dbgDebug(D_ORCHESTRATOR) << "Post installation test for the self update package succeed";
if (!changeManifestFile(temp_manifest_path)) {
dbgWarning(D_ORCHESTRATOR) << "Failed to change manifest file after update the orchestration service.";
return false;
}
dbgDebug(D_ORCHESTRATOR) << "Update the temporary manifest to be the running manifest";
string backup_file = current_file + backup_ext;
string backup_temp_file = backup_file + temp_ext;
if (!package_handler->updateSavedPackage(orch_service_name, current_file + temp_ext)) {
dbgWarning(D_ORCHESTRATOR) << "Failed to update the saved package. Package: " << orch_service_name;
return false;
}
return true;
}
bool
ManifestController::Impl::changeManifestFile(const string &new_manifest_file)
{
dbgDebug(D_ORCHESTRATOR) << "Backup the old manifest file";
auto orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<ManifestController>();
if (orchestration_tools->doesFileExist(manifest_file_path)) {
if (!orchestration_tools->copyFile(manifest_file_path,
manifest_file_path + backup_ext)) {
dbgWarning(D_ORCHESTRATOR) << "Failed to backup the old 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";
return false;
}
if (!orchestration_tools->isNonEmptyFile(manifest_file_path)) {
dbgWarning(D_ORCHESTRATOR) << "Failed to get manifest file data";
return false;
}
dbgInfo(D_ORCHESTRATOR) << "Manifest file has been updated.";
if (!orchestration_tools->removeFile(new_manifest_file)) {
dbgWarning(D_ORCHESTRATOR) << "Failed to remove new manifest file. Path: " << new_manifest_file;
}
return true;
}
bool
ManifestController::Impl::handlePackage(
const Package &package,
map<string, Package> &current_packages,
const map<string, Package> &new_packages,
map<string, Package> &corrupted_packages)
{
auto i_env = Singleton::Consume<I_Environment>::by<ManifestController>();
auto span_scope = i_env->startNewSpanScope(Span::ContextType::CHILD_OF);
dbgDebug(D_ORCHESTRATOR) << "Handling package. Package: " << package.getName();
if (!package.isInstallable().ok()) {
string report_msg =
"Skipping installation of " + package.getName() + ". Reason: " + package.isInstallable().getErr();
dbgWarning(D_ORCHESTRATOR) << report_msg;
LogGen(report_msg, Audience::SECURITY, Severity::CRITICAL, Priority::HIGH, Tags::ORCHESTRATOR);
current_packages.insert(make_pair(package.getName(), package));
return true;
}
vector<Package> installation_queue;
if (!manifest_diff_calc.buildInstallationQueue(package, installation_queue, current_packages, new_packages)) {
dbgWarning(D_ORCHESTRATOR) << "Failed building installation queue. Package: " << package.getName();
return false;
}
vector<pair<Package, string>> downloaded_files;
if (!manifest_handler.downloadPackages(installation_queue, downloaded_files)) return false;
if (!manifest_handler.installPackages(downloaded_files, current_packages, corrupted_packages)) {
LogGen(
"Failed to install package: " + package.getName(),
Audience::SECURITY,
Severity::CRITICAL,
Priority::HIGH,
Tags::ORCHESTRATOR
);
return false;
}
dbgInfo(D_ORCHESTRATOR) << "Package was installed successfully. Package: " << package.getName();
return true;
}
ManifestController::ManifestController() : Component("ManifestController"), pimpl(make_unique<Impl>()) {}
ManifestController::~ManifestController() {}
void
ManifestController::init()
{
pimpl->init();
}
SASAL_END

View File

@@ -0,0 +1,7 @@
link_directories(${BOOST_ROOT}/lib)
add_unit_test(
manifest_controller_ut
"manifest_controller_ut.cc"
"manifest_controller;logging;orchestration_modules;agent_details;agent_details_reporter;version;config;metric;event_is;-lboost_regex"
)

View File

@@ -0,0 +1,144 @@
// 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 "manifest_diff_calculator.h"
#include "debug.h"
#include "config.h"
#include "sasal.h"
using namespace std;
SASAL_START // Orchestration - Manifest Handler
USE_DEBUG_FLAG(D_ORCHESTRATOR);
void
ManifestDiffCalculator::init()
{
dbgTrace(D_ORCHESTRATOR)
<< "Initializing Manifest diff calculator, file system path prefix:: "
<< getFilesystemPathConfig();
corrupted_file_path = getConfigurationWithDefault<string>(
getFilesystemPathConfig() + "/conf/corrupted_packages.json",
"orchestration",
"Manifest corrupted files path"
);
}
// If one of the new packages is already installed, new_packages map is updated accordingly.
// This function return map<string, Package> which contain all packages that should be uninstalled
// based on new manifest
map<string, Package>
ManifestDiffCalculator::filterUntrackedPackages(
const map<string, Package> &current_packages,
map<string, Package> &new_packages)
{
dbgDebug(D_ORCHESTRATOR) << "Starting to scan old packages to remove";
map<string, Package> packages_to_remove;
for (auto current_package = current_packages.begin(); current_package != current_packages.end();) {
auto package = new_packages.find(current_package->first);
if (package == new_packages.end()) {
packages_to_remove.insert(pair<string, Package>(current_package->first, current_package->second));
} else {
if (current_package->second == package->second) {
// if package is already installed, new_packages is updated
new_packages.erase(package);
}
}
current_package++;
}
return packages_to_remove;
}
// If one of the new packages is already known as corrupted, new_packages map is
// updated accordingly.
// Otherwise, corrupted_packages is updated and old corrupted package is deleted.
bool
ManifestDiffCalculator::filterCorruptedPackages(
map<string, Package> &new_packages,
map<string, Package> &corrupted_packages)
{
bool no_corrupted_package_exist = true;
bool any_corrupted_removed = false;
for (auto corrupted_package = corrupted_packages.begin(); corrupted_package != corrupted_packages.end();) {
auto package = new_packages.find(corrupted_package->first);
if (package == new_packages.end()) {
// The corrupted package is not in the new packages list,
// so it should be removed from the corrupted list.
corrupted_package = corrupted_packages.erase(corrupted_package);
any_corrupted_removed = true;
} else {
if (corrupted_package->second == package->second) {
// The corrupted package is still in the new packages list,
// so it should be removed
dbgWarning(D_ORCHESTRATOR) << "Installation package is corrupted."
<< " Package: " << package->second.getName();
new_packages.erase(package);
corrupted_package++;
no_corrupted_package_exist = false;
} else {
// New version of corrupted package was received
corrupted_package = corrupted_packages.erase(corrupted_package);
any_corrupted_removed = true;
}
}
}
if (any_corrupted_removed) {
dbgDebug(D_ORCHESTRATOR) << "Updating corrupted file. File: " << corrupted_file_path;
auto orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<ManifestDiffCalculator>();
if (!orchestration_tools->packagesToJsonFile(corrupted_packages, corrupted_file_path)) {
dbgWarning(D_ORCHESTRATOR) << "Failed to update corrupted file. Path: " << corrupted_file_path;
return false;
}
}
return no_corrupted_package_exist;
}
// This function build the installation queue recursively and return true if succeeded, false otherwise
// At the beginning, installation_queue is empty and will be filled according package dependences
bool
ManifestDiffCalculator::buildInstallationQueue(
const Package &updated_package,
vector<Package> &installation_queue,
const map<string, Package> &current_packages,
const map<string, Package> &new_packages)
{
vector<string> requires = updated_package.getRequire();
for (size_t i = 0; i < requires.size(); i++) {
auto installed_package = current_packages.find(requires[i]);
auto new_package = new_packages.find(requires[i]);
if (installed_package == current_packages.end() ||
(new_package != new_packages.end() && *installed_package != *new_package)) {
if(!buildInstallationQueue(new_package->second,
installation_queue,
current_packages,
new_packages)) {
return false;
}
} else if (installed_package != current_packages.end()) {
dbgDebug(D_ORCHESTRATOR) << "Package is already installed. Package: " << installed_package->first;
} else if (new_package == new_packages.end()) {
dbgWarning(D_ORCHESTRATOR) << "One of the requested dependencies is corrupted or doesn't exist."
<< " Package: "<< requires[i];
return false;
}
}
installation_queue.push_back(updated_package);
return true;
}
SASAL_END

View File

@@ -0,0 +1,384 @@
// 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 "manifest_handler.h"
#include "debug.h"
#include "config.h"
#include "sasal.h"
#include "agent_details.h"
#include "orchestration_comp.h"
using namespace std;
SASAL_START // Orchestration - Manifest Handler
USE_DEBUG_FLAG(D_ORCHESTRATOR);
void
ManifestHandler::init()
{
dbgTrace(D_ORCHESTRATOR)
<< "Initializing Manifest handler, file system path prefix: "
<< getFilesystemPathConfig();
manifest_file_path = getConfigurationWithDefault<string>(
getFilesystemPathConfig() + "/conf/manifest.json",
"orchestration",
"Manifest file path"
);
temp_ext = getConfigurationWithDefault<string>("_temp", "orchestration", "Temp file extension");
backup_ext = getConfigurationWithDefault<string>(".bk", "orchestration", "Backup file extension");
packages_dir = getConfigurationWithDefault<string>(
getFilesystemPathConfig() + "/packages", "orchestration",
"Packages directory"
);
orch_service_name = getConfigurationWithDefault<string>("orchestration", "orchestration", "Service name");
default_dir = getConfigurationWithDefault<string>(
getFilesystemPathConfig(),
"orchestration",
"Default Check Point directory"
);
}
Maybe<string>
ManifestHandler::downloadPackage(const Package &package, bool is_clean_installation)
{
Maybe<string> package_download_file = genError("failed to download package, Package: " + package.getName());
Maybe<string> fog_domain = genError("No Fog domain was found");
if (Singleton::exists<I_AgentDetails>()) {
fog_domain = Singleton::Consume<I_AgentDetails>::by<ManifestHandler>()->getFogDomain();
}
if (!is_clean_installation) {
I_MainLoop *i_mainloop = Singleton::Consume<I_MainLoop>::by<ManifestHandler>();
auto pending_time_frame_seconds = getConfigurationWithDefault<int>(
60,
"orchestration",
"Download pending time frame seconds"
);
int pending_time = rand() % pending_time_frame_seconds;
dbgInfo(D_ORCHESTRATOR)
<< "Pending downloading of package "
<< package.getName()
<< " for "
<< pending_time
<< " seconds";
chrono::microseconds pending_time_micro = chrono::seconds(pending_time);
i_mainloop->yield(pending_time_micro);
dbgTrace(D_ORCHESTRATOR) << "Proceeding to package downloading. Package name " << package.getName();
}
auto orchestration_downloader = Singleton::Consume<I_Downloader>::by<ManifestHandler>();
if (!package.getRelativeDownloadPath().empty() && fog_domain.ok()) {
string download_path =
"<JWT>https://" + fog_domain.unpack() + "/download" + package.getRelativeDownloadPath();
package_download_file= orchestration_downloader->downloadFileFromURL(
download_path,
package.getChecksum(),
package.getChecksumType(),
package.getName()
);
}
if (!package_download_file.ok()) {
package_download_file = orchestration_downloader->downloadFileFromURL(
package.getDownloadPath(),
package.getChecksum(),
package.getChecksumType(),
package.getName()
);
}
return package_download_file;
}
bool
ManifestHandler::downloadPackages(
const vector<Package> &packages_to_download,
vector<pair<Package, packageFilePath>> &downloaded_packages)
{
auto i_env = Singleton::Consume<I_Environment>::by<ManifestHandler>();
auto i_orch_tools = Singleton::Consume<I_OrchestrationTools>::by<ManifestHandler>();
auto span_scope = i_env->startNewSpanScope(Span::ContextType::CHILD_OF);
for (auto &package : packages_to_download) {
dbgInfo(D_ORCHESTRATOR) << "Downloading package file." << " Package: " << package.getName();
string packages_dir = getConfigurationWithDefault<string>(
"/etc/cp/packages",
"orchestration",
"Packages directory"
);
string current_installation_file = packages_dir + "/" + package.getName() + "/" + package.getName();
bool is_clean_installation = !i_orch_tools->doesFileExist(current_installation_file);
Maybe<string> package_download_file = downloadPackage(package, is_clean_installation);
if (package_download_file.ok()) {
dbgDebug(D_ORCHESTRATOR)
<< "Installation package was downloaded successfully."
<< " Package: " << package.getName();
downloaded_packages.push_back(pair<Package, packageFilePath>(package, package_download_file.unpack()));
} else {
dbgWarning(D_ORCHESTRATOR)
<< "Failed to download installation package. "
<< "Package: " << package.getName()
<< ", Error: " << package_download_file.getErr();
for (auto &package_file : downloaded_packages) {
if (i_orch_tools->removeFile(package_file.second)) {
dbgDebug(D_ORCHESTRATOR) << "Corrupted downloaded package was removed. Package: "
<< package_file.first.getName();
} else {
dbgWarning(D_ORCHESTRATOR)
<< "Failed to removed the download file. Package: "
<< package_file.first.getName()
<< ", Path: "
<< package_file.second;
}
}
downloaded_packages.clear();
string install_error;
if (is_clean_installation) {
string error_hostname_addition = "";
auto maybe_hostname = Singleton::Consume<I_DetailsResolver>::by<ManifestHandler>()->getHostname();
if (maybe_hostname.ok()) {
error_hostname_addition = " on host '" + maybe_hostname.unpack() + "'";
}
install_error =
"Critical Error: Agent/Gateway was not fully deployed" +
error_hostname_addition +
" and is not enforcing a security policy. Retry installation or contact Check Point support.";
} else {
auto agent_details = Singleton::Consume<I_AgentDetails>::by<ManifestHandler>();
install_error =
"Warning: Agent/Gateway '" +
agent_details->getAgentId() +
"' software update failed. Agent is running previous software. Contact Check Point support.";
}
auto orchestration_status = Singleton::Consume<I_OrchestrationStatus>::by<ManifestHandler>();
if (orchestration_status->getManifestError().find("Gateway was not fully deployed") == string::npos) {
orchestration_status->setFieldStatus(
OrchestrationStatusFieldType::MANIFEST,
OrchestrationStatusResult::FAILED,
install_error
);
}
return false;
}
}
return true;
}
bool
ManifestHandler::installPackages(
const vector<pair<Package, packageFilePath>> &downloaded_package_files,
map<packageFilePath, Package> &current_packages,
map<packageFilePath, Package> &corrupted_packages)
{
auto i_env = Singleton::Consume<I_Environment>::by<ManifestHandler>();
auto span_scope = i_env->startNewSpanScope(Span::ContextType::CHILD_OF);
// Patch - reorder packages so that accessControlApp is installed before accessControlKernel
vector<pair<Package, packageFilePath>> patched_downloaded_package_files;
patched_downloaded_package_files.reserve(downloaded_package_files.size());
int ac_kernel_package_idx = -1;
int ac_app_package_idx = -1;
int i = 0;
for (auto &downloaded_package : downloaded_package_files) {
if (downloaded_package.first.getName() == "accessControlApp") {
ac_app_package_idx = i;
} else if (downloaded_package.first.getName() == "accessControlKernel") {
ac_kernel_package_idx = i;
} else {
patched_downloaded_package_files.push_back(downloaded_package);
}
i++;
}
if (ac_app_package_idx != -1) {
patched_downloaded_package_files.push_back(downloaded_package_files.at(ac_app_package_idx));
}
if (ac_kernel_package_idx != -1) {
patched_downloaded_package_files.push_back(downloaded_package_files.at(ac_kernel_package_idx));
}
auto orchestration_status = Singleton::Consume<I_OrchestrationStatus>::by<ManifestHandler>();
for (auto &downloaded_package : patched_downloaded_package_files) {
auto package = downloaded_package.first;
auto package_name = package.getName();
auto package_handler_path = downloaded_package.second;
dbgInfo(D_ORCHESTRATOR) << "Handling package installation. Package: " << package_name;
if (package_name.compare(orch_service_name) == 0) {
orchestration_status->writeStatusToFile();
bool self_update_status = selfUpdate(package, current_packages, package_handler_path);
if (!self_update_status) {
auto agent_details = Singleton::Consume<I_AgentDetails>::by<ManifestHandler>();
string install_error =
"Warning: Agent/Gateway '" +
agent_details->getAgentId() +
"' 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,
install_error
);
}
}
return self_update_status;
}
string packages_dir = getConfigurationWithDefault<string>(
"/etc/cp/packages",
"orchestration",
"Packages directory"
);
string current_installation_file = packages_dir + "/" + package_name + "/" + package_name;
auto orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<ManifestHandler>();
bool is_clean_installation = !orchestration_tools->doesFileExist(current_installation_file);
auto package_handler = Singleton::Consume<I_PackageHandler>::by<ManifestHandler>();
if (!package_handler->shouldInstallPackage(package_name, package_handler_path)) {
current_packages.insert(make_pair(package_name, package));
dbgInfo(D_ORCHESTRATOR)
<< "Skipping installation of new package with the same version as current. Package: "
<< package_name;
continue;
}
bool current_result = true;
bool is_service = package.getType() == Package::PackageType::Service;
if (is_service) {
current_result = package_handler->preInstallPackage(package_name, package_handler_path);
}
current_result = current_result && package_handler->installPackage(
package_name,
package_handler_path,
false
);
if (current_result && is_service) {
current_result = package_handler->postInstallPackage(package_name, package_handler_path);
}
if (current_result && is_service) {
current_result = package_handler->updateSavedPackage(package_name, package_handler_path);
}
if (!current_result) {
string install_error;
if (is_clean_installation) {
string error_hostname_addition = "";
auto maybe_hostname = Singleton::Consume<I_DetailsResolver>::by<ManifestHandler>()->getHostname();
if (maybe_hostname.ok()) {
error_hostname_addition = " on host '" + maybe_hostname.unpack() + "'";
}
install_error =
"Critical Error: Agent/Gateway was not fully deployed" +
error_hostname_addition +
" and is not enforcing a security policy. Retry installation or contact Check Point support.";
} else {
auto agent_details = Singleton::Consume<I_AgentDetails>::by<ManifestHandler>();
install_error =
"Warning: Agent/Gateway '" +
agent_details->getAgentId() +
"' software update failed. Agent is running previous software. Contact Check Point support.";
}
corrupted_packages.insert(make_pair(package_name, package));
dbgWarning(D_ORCHESTRATOR) << "Failed to install package. Package: " << package_name;
auto orchestration_status = Singleton::Consume<I_OrchestrationStatus>::by<ManifestHandler>();
if (orchestration_status->getManifestError().find("Gateway was not fully deployed") == string::npos) {
orchestration_status->setFieldStatus(
OrchestrationStatusFieldType::MANIFEST,
OrchestrationStatusResult::FAILED,
install_error
);
}
return false;
}
current_packages.insert(make_pair(package_name, package));
}
return true;
}
bool
ManifestHandler::uninstallPackage(Package &removed_package)
{
dbgDebug(D_ORCHESTRATOR) << "Starting uninstalling. Package: " << removed_package.getName();
string package_name = removed_package.getName();
string package_path = default_dir + "/" + package_name + "/" + package_name;
string installation_package = packages_dir + "/" + package_name + "/" + package_name;
auto package_handler = Singleton::Consume<I_PackageHandler>::by<ManifestHandler>();
return package_handler->uninstallPackage(package_name, package_path, installation_package);
}
bool
ManifestHandler::selfUpdate(
const Package &updated_package,
map<packageFilePath, Package> &current_packages,
const string &installation_file)
{
dbgInfo(D_ORCHESTRATOR) << "Updating orchestration service";
auto current_service = current_packages.find(updated_package.getName());
if (current_service != current_packages.end()) {
current_service->second = updated_package;
} else {
current_packages.insert(pair<packageFilePath, Package>(updated_package.getName(), updated_package));
}
string temp_manifest_path = manifest_file_path + temp_ext;
auto orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<ManifestHandler>();
if (!orchestration_tools->packagesToJsonFile(current_packages, temp_manifest_path)) {
dbgWarning(D_ORCHESTRATOR) << "Updating manifest temporary file has failed. File: " << temp_manifest_path;
return false;
}
string current_file = packages_dir + "/" + orch_service_name + "/" + orch_service_name;
string backup_file = current_file + backup_ext;
dbgDebug(D_ORCHESTRATOR) << "Saving the temporary backup file.";
if (orchestration_tools->doesFileExist(current_file)) {
dbgDebug(D_ORCHESTRATOR) << "Backup current installation package. Destination: " << backup_file;
if (!orchestration_tools->copyFile(current_file, backup_file + temp_ext)) {
dbgWarning(D_ORCHESTRATOR) << "Failed to backup installation file. File: " << current_file;
return false;
}
} else {
dbgDebug(D_ORCHESTRATOR) << "There is no previous version for Orchestration";
}
string current_installation_file = current_file + temp_ext;
dbgDebug(D_ORCHESTRATOR) << "Saving the installation file: " << current_installation_file;
if (!orchestration_tools->copyFile(installation_file, current_installation_file)) {
dbgWarning(D_ORCHESTRATOR) << "Failed to save the installation file: " << current_installation_file;
return false;
}
dbgDebug(D_ORCHESTRATOR) << "Starting to install the orchestration: " << current_installation_file;
auto package_handler = Singleton::Consume<I_PackageHandler>::by<ManifestHandler>();
return
package_handler->preInstallPackage(orch_service_name, current_installation_file) &&
package_handler->installPackage(orch_service_name, current_installation_file, false);
}
SASAL_END