mirror of
https://github.com/openappsec/openappsec.git
synced 2025-09-30 03:34:26 +03:00
First release of open-appsec source code
This commit is contained in:
3
components/security_apps/orchestration/package_handler/CMakeLists.txt
Executable file
3
components/security_apps/orchestration/package_handler/CMakeLists.txt
Executable file
@@ -0,0 +1,3 @@
|
||||
add_library(package_handler package_handler.cc)
|
||||
|
||||
add_subdirectory(package_handler_ut)
|
508
components/security_apps/orchestration/package_handler/package_handler.cc
Executable file
508
components/security_apps/orchestration/package_handler/package_handler.cc
Executable file
@@ -0,0 +1,508 @@
|
||||
// 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 "package_handler.h"
|
||||
#include "config.h"
|
||||
#include "sasal.h"
|
||||
#include "i_shell_cmd.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <vector>
|
||||
|
||||
SASAL_START // Orchestration - Updates Control
|
||||
|
||||
USE_DEBUG_FLAG(D_ORCHESTRATOR);
|
||||
|
||||
using namespace std;
|
||||
|
||||
#ifdef smb
|
||||
static const string InstallEnvPrefix = "TMPDIR=/storage/tmp ";
|
||||
#else
|
||||
static const string InstallEnvPrefix = "";
|
||||
#endif
|
||||
|
||||
enum class PackageHandlerActions {
|
||||
INSTALL,
|
||||
UNINSTALL,
|
||||
PREINSTALL,
|
||||
POSTINSTALL,
|
||||
UNREGISTER,
|
||||
GET_VERSION
|
||||
};
|
||||
|
||||
class AdditionalFlagsConfiguration
|
||||
{
|
||||
public:
|
||||
AdditionalFlagsConfiguration() : flags() {}
|
||||
|
||||
void
|
||||
load(cereal::JSONInputArchive &ar)
|
||||
{
|
||||
try {
|
||||
ar(cereal::make_nvp("flags", flags));
|
||||
} catch (cereal::Exception &) {
|
||||
ar.setNextName(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
const vector<string> & getFlags() const { return flags; }
|
||||
|
||||
private:
|
||||
vector<string> flags;
|
||||
};
|
||||
|
||||
class PackageHandler::Impl : Singleton::Provide<I_PackageHandler>::From<PackageHandler>
|
||||
{
|
||||
public:
|
||||
void
|
||||
init()
|
||||
{
|
||||
filesystem_prefix = getFilesystemPathConfig();
|
||||
dbgTrace(D_ORCHESTRATOR) << "Initializing Packet handler, file system path prefix: " << filesystem_prefix;
|
||||
}
|
||||
bool shouldInstallPackage(const string &package_name, const string &install_file_path) const override;
|
||||
|
||||
bool installPackage(const string &package_name, const string &install_file_path, bool restore_mode) const override;
|
||||
|
||||
bool
|
||||
uninstallPackage(
|
||||
const string &package_name,
|
||||
const string &package_path,
|
||||
const string &install_file_path
|
||||
) const override;
|
||||
|
||||
bool preInstallPackage(const string &package_name, const string &install_file_path) const override;
|
||||
|
||||
bool postInstallPackage(const string &package_name, const string &install_file_path) const override;
|
||||
|
||||
bool updateSavedPackage(const string &package_name, const string &install_file_path) const override;
|
||||
|
||||
private:
|
||||
void
|
||||
revertPackage(
|
||||
const string &package_name,
|
||||
bool restore_mode,
|
||||
const string ¤t_installation_file,
|
||||
const string &backup_installation_file
|
||||
) const;
|
||||
|
||||
bool setExecutionMode(const string &install_file_path) const;
|
||||
|
||||
string filesystem_prefix;
|
||||
};
|
||||
|
||||
static string
|
||||
packageHandlerActionsToString(PackageHandlerActions action)
|
||||
{
|
||||
switch(action) {
|
||||
case PackageHandlerActions::INSTALL: {
|
||||
string installation_mode = " --install";
|
||||
auto trusted_ca_directory = getConfiguration<string>("message", "Trusted CA directory");
|
||||
if (trusted_ca_directory.ok() && !trusted_ca_directory.unpack().empty()) {
|
||||
installation_mode += " --certs-dir ";
|
||||
installation_mode += trusted_ca_directory.unpack();
|
||||
}
|
||||
AdditionalFlagsConfiguration additional_flags = getConfigurationWithDefault<AdditionalFlagsConfiguration>(
|
||||
AdditionalFlagsConfiguration(),
|
||||
"orchestration",
|
||||
"additional flags"
|
||||
);
|
||||
for (const auto &flag : additional_flags.getFlags()) {
|
||||
installation_mode += " " + flag;
|
||||
}
|
||||
|
||||
return installation_mode;
|
||||
}
|
||||
case PackageHandlerActions::UNINSTALL: {
|
||||
return string(" --uninstall");
|
||||
}
|
||||
case PackageHandlerActions::PREINSTALL: {
|
||||
return string(" --pre_install_test");
|
||||
}
|
||||
case PackageHandlerActions::POSTINSTALL: {
|
||||
return string(" --post_install_test");
|
||||
}
|
||||
case PackageHandlerActions::UNREGISTER: {
|
||||
return string(" --un-register ");
|
||||
}
|
||||
case PackageHandlerActions::GET_VERSION: {
|
||||
return string(" --version");
|
||||
}
|
||||
}
|
||||
|
||||
dbgAssert(false) << "Package handler action is not supported. Action: " << static_cast<unsigned int>(action);
|
||||
return string();
|
||||
}
|
||||
|
||||
void
|
||||
PackageHandler::init()
|
||||
{
|
||||
pimpl->init();
|
||||
}
|
||||
|
||||
void
|
||||
PackageHandler::preload()
|
||||
{
|
||||
registerExpectedConfiguration<bool>("orchestration", "Debug mode");
|
||||
registerExpectedConfiguration<AdditionalFlagsConfiguration>("orchestration", "additional flags");
|
||||
registerExpectedConfiguration<uint>("orchestration", "Shell command execution time out");
|
||||
}
|
||||
|
||||
bool
|
||||
PackageHandler::Impl::setExecutionMode(const string &install_file_path) const
|
||||
{
|
||||
return (chmod(install_file_path.c_str(), S_IRUSR | S_IWUSR | S_IXUSR) == 0);
|
||||
}
|
||||
|
||||
bool
|
||||
PackageHandler::Impl::shouldInstallPackage(const string &package_name, const string &install_file_path) const
|
||||
{
|
||||
string packages_dir = getConfigurationWithDefault<string>(
|
||||
filesystem_prefix + "/packages",
|
||||
"orchestration",
|
||||
"Packages directory"
|
||||
);
|
||||
|
||||
I_OrchestrationTools *orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<PackageHandler>();
|
||||
string current_installation_file = packages_dir + "/" + package_name + "/" + package_name;
|
||||
if (!orchestration_tools->doesFileExist(current_installation_file)) {
|
||||
dbgDebug(D_ORCHESTRATOR) << "Clean installation - package should be installed. Package name: " << package_name;
|
||||
return true;
|
||||
}
|
||||
|
||||
setExecutionMode(current_installation_file);
|
||||
setExecutionMode(install_file_path);
|
||||
|
||||
dbgDebug(D_ORCHESTRATOR) << "Checking if new and current packages has different versions";
|
||||
|
||||
uint timeout = getConfigurationWithDefault<uint>(5000, "orchestration", "Shell command execution time out");
|
||||
static const string action = packageHandlerActionsToString(PackageHandlerActions::GET_VERSION);
|
||||
|
||||
I_ShellCmd *shell_cmd = Singleton::Consume<I_ShellCmd>::by<PackageHandler>();
|
||||
Maybe<string> current_package_version = shell_cmd->getExecOutput(current_installation_file + action, timeout);
|
||||
Maybe<string> new_package_version = shell_cmd->getExecOutput(install_file_path + action, timeout);
|
||||
|
||||
if (!current_package_version.ok()) {
|
||||
dbgWarning(D_ORCHESTRATOR)
|
||||
<< "Failed to get version of current package - Upgrade will be executed. Package name: "
|
||||
<< package_name
|
||||
<< ", Error: "
|
||||
<< current_package_version.getErr();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!new_package_version.ok()) {
|
||||
dbgWarning(D_ORCHESTRATOR)
|
||||
<< "Failed to get version of new package - Upgrade will be executed. Package name: "
|
||||
<< package_name
|
||||
<< ", Error: "
|
||||
<< new_package_version.getErr();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool should_install = current_package_version.unpack() != new_package_version.unpack();
|
||||
|
||||
dbgInfo(D_ORCHESTRATOR)
|
||||
<< "Version for both new and current version successfully extracted. Package name: "
|
||||
<< package_name
|
||||
<< ", Current version: "
|
||||
<< current_package_version.unpack()
|
||||
<< ", New version: "
|
||||
<< new_package_version.unpack()
|
||||
<< ", Should install: "
|
||||
<< (should_install ? "yes" : "no");
|
||||
|
||||
return should_install;
|
||||
}
|
||||
|
||||
bool
|
||||
PackageHandler::Impl::installPackage(
|
||||
const string &package_name,
|
||||
const string &install_file_path,
|
||||
bool restore_mode = false) const
|
||||
{
|
||||
I_OrchestrationTools *orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<PackageHandler>();
|
||||
if (!orchestration_tools->doesFileExist(install_file_path)) {
|
||||
dbgWarning(D_ORCHESTRATOR)
|
||||
<< "Installation file is not valid for update. File path: "
|
||||
<< install_file_path
|
||||
<< " , package: "
|
||||
<< package_name;
|
||||
return false;
|
||||
}
|
||||
|
||||
string packages_dir = getConfigurationWithDefault<string>(
|
||||
filesystem_prefix + "/packages",
|
||||
"orchestration",
|
||||
"Packages directory"
|
||||
);
|
||||
string backup_extension = getConfigurationWithDefault<string>(".bk", "orchestration", "Backup file extension");
|
||||
string current_installation_file = packages_dir + "/" + package_name + "/" + package_name;
|
||||
string backup_installation_file = current_installation_file + backup_extension;
|
||||
|
||||
if (restore_mode) {
|
||||
dbgDebug(D_ORCHESTRATOR) << "Installing package: " << package_name << " from backup.";
|
||||
} else {
|
||||
dbgDebug(D_ORCHESTRATOR) << "Installing package: " << package_name;
|
||||
}
|
||||
|
||||
dbgDebug(D_ORCHESTRATOR) << "Changing permissions to execute installation file " << install_file_path;
|
||||
if (!setExecutionMode(install_file_path)) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to change permission for the installation file of " << package_name;
|
||||
return false;
|
||||
}
|
||||
|
||||
dbgDebug(D_ORCHESTRATOR) << "Start running installation file. Package: "
|
||||
<< package_name
|
||||
<< ", path: "
|
||||
<< install_file_path;
|
||||
auto action = packageHandlerActionsToString(PackageHandlerActions::INSTALL);
|
||||
bool cmd_result = orchestration_tools->executeCmd(InstallEnvPrefix + install_file_path + action);
|
||||
if (!cmd_result) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed installing package: " << package_name;
|
||||
revertPackage(package_name, restore_mode, current_installation_file, backup_installation_file);
|
||||
return false;
|
||||
}
|
||||
|
||||
// In restore mode, we should exit to prevent infinite loop
|
||||
if (restore_mode) return true;
|
||||
|
||||
if (
|
||||
!orchestration_tools->doesFileExist(current_installation_file) &&
|
||||
!orchestration_tools->copyFile(install_file_path, current_installation_file)
|
||||
) {
|
||||
dbgWarning(D_ORCHESTRATOR)
|
||||
<< "Failed to save installation file. File: "
|
||||
<< install_file_path
|
||||
<< ". Target path: "
|
||||
<< current_installation_file;
|
||||
return false;
|
||||
}
|
||||
|
||||
dbgDebug(D_ORCHESTRATOR) << "Backup installation file to " << backup_installation_file;
|
||||
if (!orchestration_tools->copyFile(current_installation_file, backup_installation_file)) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to backup installation file: " << current_installation_file;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
PackageHandler::Impl::revertPackage(
|
||||
const string &package_name,
|
||||
bool restore_mode,
|
||||
const string ¤t_installation_file,
|
||||
const string &backup_installation_file) const
|
||||
{
|
||||
string orch_service_name = getConfigurationWithDefault<string>(
|
||||
"orchestration",
|
||||
"orchestration",
|
||||
"Service name"
|
||||
);
|
||||
string packages_dir = getConfigurationWithDefault<string>(
|
||||
filesystem_prefix + "/packages",
|
||||
"orchestration",
|
||||
"Packages directory"
|
||||
);
|
||||
if (package_name == orch_service_name) {
|
||||
string manifest_file_path = getConfigurationWithDefault<string>(
|
||||
filesystem_prefix + "/conf/manifest.json",
|
||||
"orchestration",
|
||||
"Manifest file path"
|
||||
);
|
||||
string temp_extension = getConfigurationWithDefault<string>("_temp", "orchestration", "Temp file extension");
|
||||
string temp_manifest_file(manifest_file_path + temp_extension);
|
||||
|
||||
I_OrchestrationTools *orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<PackageHandler>();
|
||||
orchestration_tools->removeFile(temp_manifest_file);
|
||||
}
|
||||
|
||||
if (restore_mode) return;
|
||||
|
||||
// First we try to recover to last running package and then to
|
||||
// the backup (2 recent versions are kept)
|
||||
if (!installPackage(package_name, current_installation_file, true)) {
|
||||
dbgWarning(D_ORCHESTRATOR)
|
||||
<< "Failed to recover from current installation package,"
|
||||
<< " trying to use backup package. Current package: "
|
||||
<< current_installation_file;
|
||||
if (!installPackage(package_name, backup_installation_file, true)) {
|
||||
dbgWarning(D_ORCHESTRATOR)
|
||||
<< "Failed to recover from backup installation package. Backup package: "
|
||||
<< backup_installation_file;
|
||||
} else {
|
||||
dbgInfo(D_ORCHESTRATOR)
|
||||
<< "Installation of the backup package succeeded. Backup package: "
|
||||
<< backup_installation_file;
|
||||
}
|
||||
} else {
|
||||
dbgInfo(D_ORCHESTRATOR)
|
||||
<< "Installation of the latest package succeeded. Current package: "
|
||||
<< current_installation_file;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
PackageHandler::Impl::uninstallPackage(
|
||||
const string &package_name,
|
||||
const string &package_path,
|
||||
const string &install_file_path) const
|
||||
{
|
||||
I_OrchestrationTools *orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<PackageHandler>();
|
||||
if (!orchestration_tools->doesFileExist(install_file_path)) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Installation file does not exist. File: " << install_file_path;
|
||||
return false;
|
||||
}
|
||||
|
||||
string watchdog_path = getConfigurationWithDefault<string>(
|
||||
filesystem_prefix,
|
||||
"orchestration",
|
||||
"Default Check Point directory"
|
||||
) + "/watchdog/cp-nano-watchdog";
|
||||
auto action = packageHandlerActionsToString(PackageHandlerActions::UNREGISTER);
|
||||
if (!orchestration_tools->executeCmd(InstallEnvPrefix + watchdog_path + action + package_path)) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to unregister package from watchdog. Package: " << package_name;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!setExecutionMode(install_file_path)) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to change package permission. Package: " << package_name;
|
||||
return false;
|
||||
}
|
||||
|
||||
action = packageHandlerActionsToString(PackageHandlerActions::UNINSTALL);
|
||||
if (!orchestration_tools->executeCmd(InstallEnvPrefix + install_file_path + action)) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to uninstall package. Package: " << package_name;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!orchestration_tools->removeFile(install_file_path)) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to remove installation package files. Package: " << package_name;
|
||||
}
|
||||
|
||||
string backup_ext = getConfigurationWithDefault<string>(
|
||||
".bk",
|
||||
"orchestration",
|
||||
"Backup file extension"
|
||||
);
|
||||
|
||||
if (!orchestration_tools->removeFile(install_file_path + backup_ext)) {
|
||||
dbgDebug(D_ORCHESTRATOR) << "Failed to remove backup installation package files. Package: " << package_name;
|
||||
}
|
||||
|
||||
dbgInfo(D_ORCHESTRATOR) << "Package was uninstalled successfully. Package: " << package_name;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PackageHandler::Impl::preInstallPackage(const string &package_name, const string &install_file_path) const
|
||||
{
|
||||
I_OrchestrationTools *orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<PackageHandler>();
|
||||
if (!orchestration_tools->doesFileExist(install_file_path)) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Installation file does not exist. File: " << install_file_path;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!setExecutionMode(install_file_path)) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to change package permission. Package: " << package_name;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto action = packageHandlerActionsToString(PackageHandlerActions::PREINSTALL);
|
||||
auto cmd_result = orchestration_tools->executeCmd(InstallEnvPrefix + install_file_path + action);
|
||||
if (!cmd_result) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed during pre installation test. Package: " << package_name;
|
||||
return false;
|
||||
}
|
||||
|
||||
dbgInfo(D_ORCHESTRATOR) << "Pre installation test passed successfully. Package: " << package_name;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PackageHandler::Impl::postInstallPackage(const string &package_name, const string &install_file_path) const
|
||||
{
|
||||
I_OrchestrationTools *orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<PackageHandler>();
|
||||
if (!orchestration_tools->doesFileExist(install_file_path)) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Installation file does not exist. File: " << install_file_path;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!setExecutionMode(install_file_path)) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to change package permission. Package: " << package_name;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto action = packageHandlerActionsToString(PackageHandlerActions::POSTINSTALL);
|
||||
auto cmd_result = orchestration_tools->executeCmd(InstallEnvPrefix + install_file_path + action);
|
||||
if (!cmd_result) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed during post installation test. Package: " << package_name;
|
||||
string backup_extension = getConfigurationWithDefault<string>(".bk", "orchestration", "Backup file extension");
|
||||
string packages_dir = getConfigurationWithDefault<string>(
|
||||
filesystem_prefix + "/packages",
|
||||
"orchestration",
|
||||
"Packages directory"
|
||||
);
|
||||
string current_installation_file = packages_dir + "/" + package_name + "/" + package_name;
|
||||
revertPackage(package_name, false, current_installation_file, current_installation_file + backup_extension);
|
||||
return false;
|
||||
}
|
||||
dbgInfo(D_ORCHESTRATOR) << "Post installation test passed successfully. Package: " << package_name;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PackageHandler::Impl::updateSavedPackage(const string &package_name, const string &install_file_path) const
|
||||
{
|
||||
string packages_dir = getConfigurationWithDefault<string>(
|
||||
filesystem_prefix + "/packages",
|
||||
"orchestration",
|
||||
"Packages directory"
|
||||
);
|
||||
string backup_extension = getConfigurationWithDefault<string>(".bk", "orchestration", "Backup file extension");
|
||||
string temp_extension = getConfigurationWithDefault<string>("_temp", "orchestration", "Temp file extension");
|
||||
string current_installation_file = packages_dir + "/" + package_name + "/" + package_name;
|
||||
string current_installation_file_backup = current_installation_file + backup_extension;
|
||||
string tmp_backup = current_installation_file_backup + temp_extension;
|
||||
|
||||
I_OrchestrationTools *orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<PackageHandler>();
|
||||
// Step 1 - save current installation file backup to temporary file.
|
||||
orchestration_tools->copyFile(current_installation_file_backup, tmp_backup);
|
||||
// Step 2 - save current installation file to the backuop file.
|
||||
orchestration_tools->copyFile(current_installation_file, current_installation_file_backup);
|
||||
dbgDebug(D_ORCHESTRATOR) << "Saving the installation file. "
|
||||
<< "From: " << install_file_path << ", "
|
||||
<< " To: " << current_installation_file;
|
||||
// Step 3 - save the new installation file to the saved package.
|
||||
if (!orchestration_tools->copyFile(install_file_path, current_installation_file)) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to save installation file. File: " << install_file_path;
|
||||
// Step 3.1 - Revet the backup package
|
||||
orchestration_tools->copyFile(tmp_backup, current_installation_file_backup);
|
||||
return false;
|
||||
}
|
||||
// Step 4 - remove the current package file
|
||||
if (!orchestration_tools->removeFile(install_file_path)) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to remove temporary installation file. File: " << install_file_path;
|
||||
}
|
||||
// Step 5 - remove the temporary backup file
|
||||
orchestration_tools->removeFile(tmp_backup);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PackageHandler::PackageHandler() : Component("PackageHandler"), pimpl(make_unique<Impl>()) {}
|
||||
|
||||
PackageHandler::~PackageHandler() {}
|
||||
|
||||
SASAL_END
|
@@ -0,0 +1,8 @@
|
||||
link_directories(${ng_module_osrc_openssl_path}/lib)
|
||||
link_directories(${BOOST_ROOT}/lib)
|
||||
|
||||
add_unit_test(
|
||||
package_handler_ut
|
||||
"package_handler_ut.cc"
|
||||
"package_handler;orchestration_tools;orchestration_modules;singleton;logging;config;metric;event_is;-lcrypto;-lboost_filesystem;-lboost_regex"
|
||||
)
|
@@ -0,0 +1,404 @@
|
||||
#include "package_handler.h"
|
||||
|
||||
#include "cptest.h"
|
||||
#include "config.h"
|
||||
#include "config_component.h"
|
||||
#include "mock/mock_orchestration_tools.h"
|
||||
#include "mock/mock_mainloop.h"
|
||||
#include "mock/mock_time_get.h"
|
||||
#include "mock/mock_shell_cmd.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace testing;
|
||||
|
||||
class PackageHandlerTest : public Test
|
||||
{
|
||||
public:
|
||||
PackageHandlerTest()
|
||||
:
|
||||
package_dir("/tmp/packages"),
|
||||
backup_ext(".bk")
|
||||
{
|
||||
setConfiguration<string>(package_dir, "orchestration", "Packages directory");
|
||||
setConfiguration<string>(backup_ext, "orchestration", "Backup file extension");
|
||||
setConfiguration<string>("/tmp", "orchestration", "Default Check Point directory");
|
||||
|
||||
writeFile("#!/bin/bash\necho \"bb\"\nexit 1", "/tmp/bad.sh");
|
||||
writeFile("#!/bin/bash\necho \"bb\"", "/tmp/packages/good/good");
|
||||
writeFile("#!/bin/bash\necho \"bb\"", "/tmp/good.sh");
|
||||
writeFile("#!/bin/bash\necho \"bb\"", "/tmp/packages/a/a");
|
||||
package_handler.init();
|
||||
}
|
||||
|
||||
~PackageHandlerTest()
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
fs::path path_to_clean(package_dir);
|
||||
if (fs::is_directory(path_to_clean)) {
|
||||
for (fs::directory_iterator iter(path_to_clean); iter != fs::directory_iterator(); ++iter) {
|
||||
fs::remove_all(iter->path());
|
||||
}
|
||||
fs::remove_all(package_dir);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
preload()
|
||||
{
|
||||
package_handler.preload();
|
||||
}
|
||||
|
||||
bool
|
||||
writeFile(const string &text, const string &path) const
|
||||
{
|
||||
if (path.find('/') != string::npos) {
|
||||
try {
|
||||
string dir_path = path.substr(0, path.find_last_of('/'));
|
||||
boost::filesystem::create_directories(dir_path);
|
||||
} catch (const boost::filesystem::filesystem_error& e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
try {
|
||||
ofstream fout(path);
|
||||
fout << text;
|
||||
return true;
|
||||
} catch (const boost::filesystem::filesystem_error& e) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
string package_dir;
|
||||
string backup_ext;
|
||||
::Environment env;
|
||||
ConfigComponent config;
|
||||
NiceMock<MockOrchestrationTools> mock_orchestration_tools;
|
||||
PackageHandler package_handler;
|
||||
I_PackageHandler *i_package_handler = Singleton::Consume<I_PackageHandler>::from(package_handler);
|
||||
NiceMock<MockMainLoop> mock_mainloop;
|
||||
NiceMock<MockTimeGet> mock_timer;
|
||||
StrictMock<MockShellCmd> mock_shell;
|
||||
};
|
||||
|
||||
TEST_F(PackageHandlerTest, doNothing)
|
||||
{
|
||||
}
|
||||
|
||||
TEST_F(PackageHandlerTest, registerExpectedConfig)
|
||||
{
|
||||
env.preload();
|
||||
env.init();
|
||||
|
||||
preload();
|
||||
string config_json =
|
||||
"{\n"
|
||||
" \"orchestration\": {\n"
|
||||
" \"Debug mode\": [\n"
|
||||
" {\n"
|
||||
" \"value\": true\n"
|
||||
" }\n"
|
||||
" ]\n"
|
||||
" }\n"
|
||||
"}";
|
||||
|
||||
istringstream string_stream(config_json);
|
||||
Singleton::Consume<Config::I_Config>::from(config)->loadConfiguration(string_stream);
|
||||
EXPECT_THAT(getConfiguration<bool>("orchestration", "Debug mode"), IsValue(true));
|
||||
env.fini();
|
||||
}
|
||||
|
||||
TEST_F(PackageHandlerTest, useAdditionalFlags)
|
||||
{
|
||||
env.preload();
|
||||
env.init();
|
||||
preload();
|
||||
registerExpectedConfiguration<string>("orchestration", "Packages directory");
|
||||
registerExpectedConfiguration<string>("orchestration", "Backup file extension");
|
||||
registerExpectedConfiguration<string>("orchestration", "Default Check Point directory");
|
||||
|
||||
string config_json =
|
||||
"{\n"
|
||||
" \"orchestration\": {\n"
|
||||
" \"additional flags\": [\n"
|
||||
" {\n"
|
||||
" \"flags\": [\n"
|
||||
" \"--flag1\",\n"
|
||||
" \"--flag2\"\n"
|
||||
" ]\n"
|
||||
" }\n"
|
||||
" ],\n"
|
||||
" \"Packages directory\": [ { \"value\": \"" + package_dir + "\"}],\n"
|
||||
" \"Backup file extension\": [ { \"value\": \"" + backup_ext + "\"}],\n"
|
||||
" \"Default Check Point directory\": [ { \"value\": \"/tmp\"}]"
|
||||
" }\n"
|
||||
"}";
|
||||
istringstream string_stream(config_json);
|
||||
Singleton::Consume<Config::I_Config>::from(config)->loadConfiguration(string_stream);
|
||||
|
||||
string script_path = "/tmp/good.sh";
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(script_path)).WillOnce(Return(true));
|
||||
string package_file = package_dir + "/a/a";
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(package_file)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(package_file, package_file + backup_ext)).WillOnce(Return(true));
|
||||
|
||||
string install_command = script_path + " --install --flag1 --flag2";
|
||||
EXPECT_CALL(mock_orchestration_tools, executeCmd(install_command)).WillOnce(Return(true));
|
||||
EXPECT_TRUE(i_package_handler->installPackage("a", script_path, false));
|
||||
|
||||
env.fini();
|
||||
}
|
||||
|
||||
TEST_F(PackageHandlerTest, fileNotExist)
|
||||
{
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist("test.json")).WillOnce(Return(false));
|
||||
EXPECT_NE(true, i_package_handler->installPackage("", "test.json", false));
|
||||
}
|
||||
|
||||
TEST_F(PackageHandlerTest, goodInstall)
|
||||
{
|
||||
string script_path = "/tmp/good.sh";
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(script_path)).WillOnce(Return(true));
|
||||
string package_file = package_dir + "/a/a";
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(package_file)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(package_file, package_file + backup_ext)).WillOnce(Return(true));
|
||||
|
||||
string command = script_path + " --install";
|
||||
EXPECT_CALL(mock_orchestration_tools, executeCmd(command)).WillOnce(Return(true));
|
||||
EXPECT_TRUE(i_package_handler->installPackage("a", script_path, false));
|
||||
}
|
||||
|
||||
TEST_F(PackageHandlerTest, badInstall)
|
||||
{
|
||||
string package_name = "a";
|
||||
string package_file = package_dir + "/" + package_name + "/" + package_name;
|
||||
string script_path = "/tmp/bad.sh";
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(script_path)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(package_file)).WillOnce(Return(false));
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(package_file + backup_ext)).WillOnce(Return(false));
|
||||
string command = script_path + " --install";
|
||||
EXPECT_CALL(mock_orchestration_tools, executeCmd(command)).WillOnce(Return(false));
|
||||
EXPECT_FALSE(i_package_handler->installPackage(package_name, script_path, false));
|
||||
}
|
||||
|
||||
TEST_F(PackageHandlerTest, orcInstallErrorWhileCopyCurrent)
|
||||
{
|
||||
string script_path = "/tmp/good.sh";
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(script_path)).WillOnce(Return(true));
|
||||
string package_file = package_dir + "/a/a";
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(package_file)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(package_file, package_file + backup_ext)).WillOnce(Return(false));
|
||||
|
||||
string command = script_path + " --install";
|
||||
EXPECT_CALL(mock_orchestration_tools, executeCmd(command)).WillOnce(Return(true));
|
||||
EXPECT_FALSE(i_package_handler->installPackage("a", script_path, false));
|
||||
}
|
||||
|
||||
TEST_F(PackageHandlerTest, orcInstallErrorWhileRemovingNew)
|
||||
{
|
||||
string script_path = "/tmp/good.sh";
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(script_path)).WillOnce(Return(true));
|
||||
string package_file = package_dir + "/a/a";
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(package_file)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(package_file, package_file + backup_ext)).WillOnce(Return(true));
|
||||
|
||||
string command = script_path + " --install";
|
||||
EXPECT_CALL(mock_orchestration_tools, executeCmd(command)).WillOnce(Return(true));
|
||||
EXPECT_TRUE(i_package_handler->installPackage("a", script_path, false));
|
||||
}
|
||||
TEST_F(PackageHandlerTest, badInstallAndRecovery)
|
||||
{
|
||||
string package_name = "a";
|
||||
string package_file = package_dir + "/" + package_name + "/" + package_name;
|
||||
string script_path = "/tmp/bad.sh";
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(script_path)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(package_file)).WillOnce(Return(true));
|
||||
|
||||
string command = script_path + " --install";
|
||||
EXPECT_CALL(mock_orchestration_tools, executeCmd(command)).WillOnce(Return(false));
|
||||
|
||||
command = package_file + " --install";
|
||||
EXPECT_CALL(mock_orchestration_tools, executeCmd(command)).WillOnce(Return(true));
|
||||
|
||||
EXPECT_FALSE(i_package_handler->installPackage(package_name, script_path, false));
|
||||
}
|
||||
|
||||
TEST_F(PackageHandlerTest, badOrcInstallAndRecoveryWithDefualValuesChange)
|
||||
{
|
||||
setConfiguration<string>("good", "orchestration", "Service name");
|
||||
string manifest_file_path = getConfigurationWithDefault<string>("/etc/cp/conf/manifest.json",
|
||||
"orchestration", "Manifest file path");
|
||||
string temp_ext = getConfigurationWithDefault<string>("_temp", "orchestration", "Temp file extension");
|
||||
string temp_manifest_file = manifest_file_path + temp_ext;
|
||||
string package_file = package_dir + "/good/good";
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist("/tmp/bad.sh")).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(package_file)).WillOnce(Return(true));
|
||||
|
||||
string command = "/tmp/bad.sh --install";
|
||||
EXPECT_CALL(mock_orchestration_tools, executeCmd(command)).WillOnce(Return(false));
|
||||
|
||||
command = package_file + " --install";
|
||||
EXPECT_CALL(mock_orchestration_tools, executeCmd(command)).WillOnce(Return(true));
|
||||
|
||||
EXPECT_FALSE(i_package_handler->installPackage("good", "/tmp/bad.sh", false));
|
||||
}
|
||||
|
||||
TEST_F(PackageHandlerTest, shouldInstall)
|
||||
{
|
||||
string old_script_path = "/tmp/packages/my-script/my-script";
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(old_script_path)).WillOnce(Return(true));
|
||||
string new_script_path = "/tmp/new-script.sh";
|
||||
string version_command = " --version";
|
||||
EXPECT_CALL(mock_shell, getExecOutput(old_script_path + version_command, 5000, _)).WillOnce(Return(string("a")));
|
||||
EXPECT_CALL(mock_shell, getExecOutput(new_script_path + version_command, 5000, _)).WillOnce(Return(string("b")));
|
||||
|
||||
EXPECT_TRUE(i_package_handler->shouldInstallPackage("my-script", new_script_path));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(old_script_path)).WillOnce(Return(false));
|
||||
EXPECT_TRUE(i_package_handler->shouldInstallPackage("my-script", new_script_path));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(old_script_path)).WillOnce(Return(true));
|
||||
EXPECT_CALL(
|
||||
mock_shell,
|
||||
getExecOutput(old_script_path + version_command, 5000, _)
|
||||
).WillOnce(Return(Maybe<string>(genError("Failed"))));
|
||||
EXPECT_CALL(mock_shell, getExecOutput(new_script_path + version_command, 5000, _)).WillOnce(Return(string("a")));
|
||||
EXPECT_TRUE(i_package_handler->shouldInstallPackage("my-script", new_script_path));
|
||||
}
|
||||
|
||||
TEST_F(PackageHandlerTest, shouldNotInstall)
|
||||
{
|
||||
string old_script_path = "/tmp/packages/my-script/my-script";
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(old_script_path)).WillOnce(Return(true));
|
||||
string version_command = " --version";
|
||||
EXPECT_CALL(mock_shell, getExecOutput(old_script_path + version_command, 5000, _)).WillOnce(Return(string("a")));
|
||||
string new_script_path = "/tmp/new-script.sh";
|
||||
EXPECT_CALL(mock_shell, getExecOutput(new_script_path + version_command, 5000, _)).WillOnce(Return(string("a")));
|
||||
EXPECT_FALSE(i_package_handler->shouldInstallPackage("my-script", new_script_path));
|
||||
}
|
||||
|
||||
TEST_F(PackageHandlerTest, badPreInstall)
|
||||
{
|
||||
string script_path = "/tmp/bad.sh";
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(script_path)).WillOnce(Return(false));
|
||||
EXPECT_FALSE(i_package_handler->preInstallPackage("a", script_path));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(script_path)).WillOnce(Return(true));
|
||||
string command = script_path + " --pre_install_test";
|
||||
EXPECT_CALL(mock_orchestration_tools, executeCmd(command)).WillOnce(Return(false));
|
||||
EXPECT_FALSE(i_package_handler->preInstallPackage("a", script_path));
|
||||
}
|
||||
|
||||
TEST_F(PackageHandlerTest, goodPreInstall)
|
||||
{
|
||||
string script_path = "/tmp/good.sh";
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(script_path)).WillOnce(Return(true));
|
||||
string command = script_path + " --pre_install_test";
|
||||
EXPECT_CALL(mock_orchestration_tools, executeCmd(command)).WillOnce(Return(true));
|
||||
EXPECT_TRUE(i_package_handler->preInstallPackage("a", script_path));
|
||||
}
|
||||
|
||||
TEST_F(PackageHandlerTest, badPostInstall)
|
||||
{
|
||||
string script_path = "/tmp/bad.sh";
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(script_path)).WillOnce(Return(false));
|
||||
EXPECT_FALSE(i_package_handler->postInstallPackage("a", script_path));
|
||||
|
||||
string package_file = package_dir + "/a/a";
|
||||
string command = script_path + " --post_install_test";
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(script_path)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, executeCmd(command)).WillOnce(Return(false));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(package_file)).WillOnce(Return(true));
|
||||
command = package_file + " --install";
|
||||
EXPECT_CALL(mock_orchestration_tools, executeCmd(command)).WillOnce(Return(true));
|
||||
|
||||
EXPECT_FALSE(i_package_handler->postInstallPackage("a", script_path));
|
||||
}
|
||||
|
||||
TEST_F(PackageHandlerTest, goodPostInstall)
|
||||
{
|
||||
string script_path = "/tmp/good.sh";
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(script_path)).WillOnce(Return(true));
|
||||
string package_file = package_dir + "/a/a";
|
||||
string command = script_path + " --post_install_test";
|
||||
EXPECT_CALL(mock_orchestration_tools, executeCmd(command)).WillOnce(Return(true));
|
||||
EXPECT_TRUE(i_package_handler->postInstallPackage("a", script_path));
|
||||
}
|
||||
|
||||
TEST_F(PackageHandlerTest, badUninstall)
|
||||
{
|
||||
string script_path = "/tmp/good.sh";
|
||||
string watchdog_dir = "/tmp/watchdog";
|
||||
string watchdog_path = watchdog_dir + "/cp-nano-watchdog";
|
||||
string package_file = package_dir + "/a/a";
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(script_path)).WillOnce(Return(false));
|
||||
EXPECT_FALSE(i_package_handler->uninstallPackage("a", package_file, script_path));
|
||||
|
||||
string command = watchdog_path + " --un-register " + package_file;
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(script_path)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, executeCmd(command)).WillOnce(Return(false));
|
||||
EXPECT_FALSE(i_package_handler->uninstallPackage("a", package_file, script_path));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(script_path)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, executeCmd(command)).WillOnce(Return(true));
|
||||
command = script_path + " --uninstall";
|
||||
EXPECT_CALL(mock_orchestration_tools, executeCmd(command)).WillOnce(Return(false));
|
||||
EXPECT_FALSE(i_package_handler->uninstallPackage("a", package_file, script_path));
|
||||
}
|
||||
|
||||
TEST_F(PackageHandlerTest, goodUninstall)
|
||||
{
|
||||
string script_path = "/tmp/good.sh";
|
||||
string watchdog_dir = "/tmp/watchdog";
|
||||
string watchdog_path = watchdog_dir + "/cp-nano-watchdog";
|
||||
string package_file = package_dir + "/a/a";
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(script_path)).WillOnce(Return(true));
|
||||
|
||||
string command = watchdog_path + " --un-register " + package_file;
|
||||
EXPECT_CALL(mock_orchestration_tools, executeCmd(command)).WillOnce(Return(true));
|
||||
|
||||
command = script_path + " --uninstall";
|
||||
EXPECT_CALL(mock_orchestration_tools, executeCmd(command)).WillOnce(Return(true));
|
||||
EXPECT_TRUE(i_package_handler->uninstallPackage("a", package_file, script_path));
|
||||
}
|
||||
|
||||
TEST_F(PackageHandlerTest, badupdateSavedPackage)
|
||||
{
|
||||
string script_path = "/tmp/good.sh";
|
||||
string package_file = package_dir + "/a/a";
|
||||
string package_file_backup = package_dir + "/a/a.bk";
|
||||
string package_file_backup_temp = package_dir + "/a/a.bk_temp";
|
||||
EXPECT_CALL(mock_orchestration_tools,
|
||||
copyFile(package_file_backup, package_file_backup_temp)).Times(2).WillRepeatedly(Return(false));
|
||||
EXPECT_CALL(mock_orchestration_tools,
|
||||
copyFile(package_file, package_file_backup)).Times(2).WillRepeatedly(Return(false));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(script_path, package_file)).WillOnce(Return(false));
|
||||
EXPECT_CALL(mock_orchestration_tools,
|
||||
copyFile(package_file_backup_temp, package_file_backup)).WillOnce(Return(false));
|
||||
EXPECT_FALSE(i_package_handler->updateSavedPackage("a", script_path));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(script_path, package_file)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, removeFile(script_path)).WillOnce(Return(false));
|
||||
EXPECT_CALL(mock_orchestration_tools, removeFile(package_file_backup_temp)).WillOnce(Return(false));
|
||||
EXPECT_TRUE(i_package_handler->updateSavedPackage("a", script_path));
|
||||
}
|
||||
|
||||
TEST_F(PackageHandlerTest, goodupdateSavedPackage)
|
||||
{
|
||||
string script_path = "/tmp/good.sh";
|
||||
string package_file = package_dir + "/a/a";
|
||||
string package_file_backup = package_dir + "/a/a.bk";
|
||||
string package_file_backup_temp = package_dir + "/a/a.bk_temp";
|
||||
EXPECT_CALL(mock_orchestration_tools,
|
||||
copyFile(package_file_backup, package_file_backup_temp)).WillOnce(Return(false));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(package_file, package_file_backup)).WillOnce(Return(false));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(script_path, package_file)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, removeFile(script_path)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, removeFile(package_file_backup_temp)).WillOnce(Return(true));
|
||||
|
||||
EXPECT_TRUE(i_package_handler->updateSavedPackage("a", script_path));
|
||||
}
|
Reference in New Issue
Block a user