Jul 5th update

This commit is contained in:
Ned Wright
2023-07-05 23:32:39 +00:00
parent 22f1a984aa
commit a59f079ef7
85 changed files with 2488 additions and 1754 deletions

View File

@@ -5,7 +5,6 @@ add_subdirectory(signal_handler)
add_subdirectory(gradual_deployment)
add_subdirectory(packet)
add_subdirectory(pending_key)
add_subdirectory(messaging_downloader)
add_subdirectory(health_check_manager)
add_subdirectory(utils)

View File

@@ -52,14 +52,14 @@ NginxAttachmentOpaque::NginxAttachmentOpaque(HttpTransactionData _transaction_da
ctx.registerValue("eventReferenceId", uuid, EnvKeyAttr::LogSection::DATA);
ctx.registerValue<string>(HttpTransactionData::http_proto_ctx, transaction_data.getHttpProtocol());
ctx.registerValue<string>(HttpTransactionData::method_ctx, transaction_data.getHttpMethod());
ctx.registerValue<string>(HttpTransactionData::host_name_ctx, transaction_data.getDestinationHost());
ctx.registerValue<string>(HttpTransactionData::host_name_ctx, transaction_data.getParsedHost());
ctx.registerValue<uint16_t>(HttpTransactionData::listening_port_ctx, transaction_data.getListeningPort());
ctx.registerValue<IPAddr>(HttpTransactionData::listening_ip_ctx, transaction_data.getListeningIP());
ctx.registerValue<IPAddr>(HttpTransactionData::client_ip_ctx, transaction_data.getSourceIP());
ctx.registerValue<uint16_t>(HttpTransactionData::client_port_ctx, transaction_data.getSourcePort());
ctx.registerFunc<string>(HttpTransactionData::source_identifier, [this](){ return source_identifier; });
ctx.registerValue<string>(HttpTransactionData::uri_ctx, transaction_data.getURI());
ctx.registerValue<string>(HttpTransactionData::uri_ctx, transaction_data.getParsedURI());
auto decoder = makeVirtualContainer<HexDecoder<'%'>>(transaction_data.getURI());
string decoded_url(decoder.begin(), decoder.end());
auto question_mark_location = decoded_url.find('?');

View File

@@ -43,6 +43,19 @@ public:
uint16_t client_port
);
HttpTransactionData (
std::string http_proto,
std::string method,
std::string host_name,
std::string parsed_host,
IPAddr listening_ip,
uint16_t listening_port,
std::string uri,
std::string parsed_uri,
IPAddr client_ip,
uint16_t client_port
);
// LCOV_EXCL_START - sync functions, can only be tested once the sync module exists
template <class Archive>
void
@@ -52,9 +65,11 @@ public:
http_proto,
method,
host_name,
parsed_host,
listening_ip,
listening_port,
uri,
parsed_uri,
client_ip,
client_port,
response_content_encoding
@@ -69,9 +84,11 @@ public:
http_proto,
method,
host_name,
parsed_host,
listening_ip,
listening_port,
uri,
parsed_uri,
client_ip,
client_port,
response_content_encoding
@@ -86,8 +103,10 @@ public:
const IPAddr & getListeningIP() const { return listening_ip; }
uint16_t getListeningPort() const { return listening_port; }
const std::string & getDestinationHost() const { return host_name; }
const std::string & getParsedHost() const { return parsed_host; }
const std::string & getHttpProtocol() const { return http_proto; }
const std::string & getURI() const { return uri; }
const std::string & getParsedURI() const { return parsed_uri; }
const std::string & getHttpMethod() const { return method; }
void print(std::ostream &out_stream) const;
@@ -124,9 +143,11 @@ private:
std::string http_proto;
std::string method = "GET";
std::string host_name;
std::string parsed_host;
IPAddr listening_ip;
uint16_t listening_port;
std::string uri;
std::string parsed_uri;
IPAddr client_ip;
uint16_t client_port;
bool is_request;

View File

@@ -51,6 +51,8 @@ public:
virtual void clearFailedServices() = 0;
virtual std::set<std::string> && moveChangedPolicies() = 0;
virtual bool isServiceInstalled(const std::string &service_name) = 0;
virtual void registerServiceConfig(

View File

@@ -14,7 +14,6 @@
#ifndef __ORCHESTRATION_COMP_H__
#define __ORCHESTRATION_COMP_H__
#include "i_messaging_downloader.h"
#include "i_messaging.h"
#include "i_mainloop.h"
#include "i_shell_cmd.h"
@@ -49,7 +48,6 @@ class OrchestrationComp
Singleton::Consume<I_DetailsResolver>,
Singleton::Consume<I_RestApi>,
Singleton::Consume<I_TenantManager>,
Singleton::Consume<I_MessagingDownloader>,
Singleton::Consume<I_PackageHandler>,
Singleton::Consume<I_ServiceController>,
Singleton::Consume<I_UpdateCommunication>,

View File

@@ -1,4 +0,0 @@
add_library(messaging_downloader_server messaging_downloader_server.cc)
add_library(messaging_downloader_client messaging_downloader_client.cc)
add_subdirectory(messaging_downloader_ut)

View File

@@ -1,230 +0,0 @@
// 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 <unordered_map>
#include "messaging_downloader_client.h"
#include "i_messaging.h"
#include "config.h"
#include "rest.h"
USE_DEBUG_FLAG(D_COMMUNICATION);
using namespace std;
class MessagingDownloaderClientRequest : public ClientRest
{
public:
MessagingDownloaderClientRequest()
{
file_name = "";
url = "";
port = 80;
response_port = 0;
status = false;
}
MessagingDownloaderClientRequest(
const string &_file_name,
const string &_url,
const unsigned int _port,
const unsigned int _response_port
) :
file_name(_file_name),
url(_url),
port(_port),
response_port(_response_port),
status(false)
{}
bool getStatus() const { return status.get(); }
const string & getUuid() const { return uuid.get(); }
C2S_PARAM(string, file_name);
C2S_PARAM(string, url);
C2S_PARAM(unsigned int, port);
C2S_PARAM(unsigned int, response_port);
S2C_PARAM(string, uuid);
S2C_PARAM(bool, status);
};
class DownloaderCbHandler
{
public:
void
addCallback(const string &uuid, I_MessagingDownloader::OnCompleteCB &cb)
{
DownloaderCbHandler::uuid_to_cb[uuid] = cb;
}
static void
handleDownloadCB(const string &uuid, Maybe<string> &downloaded_file)
{
dbgTrace(D_COMMUNICATION) << "Handling downloading complete callback. UUID: " << uuid;
if(DownloaderCbHandler::uuid_to_cb.find(uuid) == DownloaderCbHandler::uuid_to_cb.end()) {
dbgWarning(D_COMMUNICATION) << "Failed to execute download completion callback.";
return;
}
if (DownloaderCbHandler::uuid_to_cb.at(uuid) != nullptr) {
DownloaderCbHandler::uuid_to_cb.at(uuid)(downloaded_file);
DownloaderCbHandler::uuid_to_cb.erase(uuid);
} else {
string curr_status;
if (downloaded_file.ok()) {
curr_status = ". File path: " + downloaded_file.unpack();
} else {
curr_status = ". Error: " + downloaded_file.getErr();
}
dbgWarning(D_COMMUNICATION)
<< "Illegal download completion callback for downloading process with UUID: "
<< uuid
<< curr_status;
}
dbgTrace(D_COMMUNICATION) << "Successfully handled the downloading complete callback. UUID: " << uuid;
}
static unordered_map<string, I_MessagingDownloader::OnCompleteCB> uuid_to_cb;
};
unordered_map<string, I_MessagingDownloader::OnCompleteCB> DownloaderCbHandler::uuid_to_cb;
class MessagingDownloaderClientRes : public ServerRest
{
public:
void
doCall() override
{
dbgTrace(D_COMMUNICATION) << "Received response from the downloading server.";
if (status.get() && filepath.isActive()) {
Maybe<string> response(filepath.get());
DownloaderCbHandler::handleDownloadCB(uuid.get(), response);
} else {
if (!error.isActive()) error = "unknown error";
dbgWarning(D_COMMUNICATION) << "Failed to download. Error: " << error.get();
Maybe<string> response = genError(error.get());
DownloaderCbHandler::handleDownloadCB(uuid.get(), response);
}
}
C2S_PARAM(string, uuid);
C2S_PARAM(bool, status);
C2S_OPTIONAL_PARAM(string, filepath);
C2S_OPTIONAL_PARAM(string, error);
};
class MessagingDownloaderClient::Impl : Singleton::Provide<I_MessagingDownloader>::From<MessagingDownloaderClient>
{
public:
void
init()
{
i_msg = Singleton::Consume<I_Messaging>::by<MessagingDownloaderClient>();
Singleton::Consume<I_RestApi>::by<MessagingDownloaderClient>()->addRestCall<MessagingDownloaderClientRes>(
RestAction::SHOW,
"download-status"
);
}
void
fini()
{
i_msg = nullptr;
}
bool
downloadFile(
const string &file_name,
const string &url,
I_MessagingDownloader::OnCompleteCB cb = nullptr,
const unsigned int port = 0
) override
{
dbgTrace(D_COMMUNICATION)
<< "Processing new download request."
<< "File name: "
<< file_name
<< "URL: "
<< url;
auto response_port = Singleton::Consume<I_Environment>::by<MessagingDownloaderClient>()->get<int>(
"Listening Port"
);
if (!response_port.ok()) {
dbgWarning(D_COMMUNICATION) << "Failed to get the service listening port.";
return false;
}
vector<int> download_ports = {
getConfigurationWithDefault(8164, "Downloader", "Downloader Primary Port"),
getConfigurationWithDefault(8167, "Downloader", "Downloader Secondary Port")
};
MessagingDownloaderClientRequest download_obj(
file_name,
url,
port,
response_port.unpack()
);
Flags<MessageConnConfig> conn_flags;
conn_flags.setFlag(MessageConnConfig::EXPECT_REPLY);
if (i_msg != nullptr) {
dbgTrace(D_COMMUNICATION) << "Sending request to the downloading service.";
bool res = false;
for (int port: download_ports) {
dbgTrace(D_COMMUNICATION) << "Trying to request downloading with downloading service port " << port;
res = i_msg->sendObject(
download_obj,
I_Messaging::Method::POST,
"127.0.0.1",
port,
conn_flags,
"/add-download-file"
);
if (res) break;
}
if (!res) {
dbgInfo(D_COMMUNICATION) << "Failed to request for file downloading";
return false;
}
dbgTrace(D_COMMUNICATION) << "Successfully requested for downloading.";
cb_handler.addCallback(download_obj.getUuid(), cb);
} else {
dbgDebug(D_COMMUNICATION) << "Failed to request downloading. Illegal messaging infrastructure.";
}
return download_obj.getStatus();
}
private:
I_Messaging *i_msg;
DownloaderCbHandler cb_handler;
};
MessagingDownloaderClient::MessagingDownloaderClient()
:
Component("MessagingDownloaderClient"),
pimpl(make_unique<Impl>())
{}
MessagingDownloaderClient::~MessagingDownloaderClient() {}
void MessagingDownloaderClient::init() { pimpl->init(); }
void MessagingDownloaderClient::fini() { pimpl->fini(); }
void
MessagingDownloaderClient::preload()
{
registerExpectedConfiguration<int>("Downloader", "Downloader Primary Port");
registerExpectedConfiguration<int>("Downloader", "Downloader Secondary Port");
};

View File

@@ -1,375 +0,0 @@
// 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 "messaging_downloader_server.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <sstream>
#include <set>
#include "i_messaging.h"
#include "rest.h"
#include "config.h"
#include "url_parser.h"
#include "agent_core_utilities.h"
USE_DEBUG_FLAG(D_COMMUNICATION);
using namespace std;
class MessagingDownloaderResponser : public ClientRest
{
public:
MessagingDownloaderResponser()=delete;
MessagingDownloaderResponser(string &_uuid, const Maybe<string> &_filepath)
:
uuid(_uuid),
status(_filepath.ok())
{
if (_filepath.ok()) {
filepath = _filepath.unpack();
} else {
error = _filepath.getErr();
}
}
C2S_PARAM(string, uuid);
C2S_PARAM(bool, status);
C2S_OPTIONAL_PARAM(string, filepath)
C2S_OPTIONAL_PARAM(string, error)
};
class MessagingDownloaderReceiver : public ServerRest
{
public:
void
doCall() override
{
dbgTrace(D_COMMUNICATION) << "Received new downloading request.";
stringstream uuid_ss;
uuid_ss << boost::uuids::random_generator()();
uuid = uuid_ss.str();
if (!port.isActive()) {
dbgTrace(D_COMMUNICATION) << "Request does not contain explicit port.";
port = 0;
}
dbgInfo(D_COMMUNICATION)
<< "Downloading a file and using the next parameters: "
<< "file_name: "
<< file_name.get()
<< ", url: "
<< url.get()
<< ", uuid: "
<< uuid.get()
<< ", port: "
<< port.get()
<< ", notification port: "
<< response_port.get();
unsigned int response_port_cap = response_port.get();
string uuid_capture = uuid.get();
status = Singleton::Consume<I_MessagingDownloader>::from<MessagingDownloaderServer>()->downloadFile(
file_name.get(),
url.get(),
[uuid_capture, response_port_cap](const Maybe<string> &downloaded_file) mutable
{
Flags<MessageConnConfig> conn_flags;
MessagingDownloaderResponser res(uuid_capture, downloaded_file);
dbgTrace(D_COMMUNICATION) << "Sending the download status to the client.";
bool res_status = Singleton::Consume<I_Messaging>::by<MessagingDownloaderServer>()->sendNoReplyObject(
res,
I_Messaging::Method::POST,
"127.0.0.1",
response_port_cap,
conn_flags,
"/show-download-status"
);
if (!res_status) {
dbgInfo(D_COMMUNICATION) << "Failed to send the download status.";
} else {
dbgDebug(D_COMMUNICATION)
<< "Successfully sent the download status. Notification port: "
<< response_port_cap
<< ", Status: "
<< downloaded_file.ok();
}
},
port.get()
);
}
C2S_PARAM(string, file_name);
C2S_PARAM(string, url);
C2S_PARAM(int, response_port);
C2S_PARAM(int, port);
S2C_PARAM(string, uuid);
S2C_PARAM(bool, status);
};
class DownloadingInstance
{
public:
DownloadingInstance()=default;
DownloadingInstance(
const string &_file_name,
const string &_url,
const unsigned int _port
) :
file_name(_file_name),
url(_url),
port(_port),
url_parser(_url)
{
parseURL();
}
Maybe<string>
genJson() const
{
return string("");
}
bool
loadJson(const string &_body)
{
body = vector<char>(_body.begin(), _body.end());
return true;
}
const vector<char> &
getResponse() const
{
return body;
}
bool
operator==(const DownloadingInstance &other) const
{
return file_name == other.file_name &&
host == other.host &&
url == other.url &&
port == other.port &&
is_secure == other.is_secure &&
origin_is_fog == other.origin_is_fog;
}
bool
operator<(const DownloadingInstance &other) const
{
return file_name < other.file_name ||
host < other.host ||
url < other.url ||
port < other.port ||
is_secure < other.is_secure ||
origin_is_fog < other.origin_is_fog;
}
const string & getFileName() const { return file_name; }
const string & getHost() const { return host; }
const string & getUrl() const { return url; }
unsigned int getPort() const { return port; }
bool getIsSecure() const { return is_secure; }
bool getIsFogOrigin() const { return origin_is_fog; }
private:
void
parseURL()
{
dbgTrace(D_COMMUNICATION) << "Parsing the URL to extract the relevant info. URL: " << url;
origin_is_fog = false;
auto maybe_host = url_parser.getBaseURL();
if (!maybe_host.ok()) {
dbgWarning(D_COMMUNICATION) << "Failed to parse the URL";
return;
}
host = maybe_host.unpack();
is_secure = url_parser.isOverSSL();
if (port == 0 && url_parser.getPort() != "") {
try {
port = stoi(url_parser.getPort());
} catch (exception &e) {
port = 443;
dbgInfo(D_COMMUNICATION)
<< "Failed to parse the port for the downloading request. Error "
<< e.what()
<< ". Using the default port "
<< port;
}
} else {
dbgTrace(D_COMMUNICATION) << "Using explicitly defined port. Port: " << port;
}
I_AgentDetails *agent_details = Singleton::Consume<I_AgentDetails>::by<MessagingDownloaderServer>();
if (agent_details->getFogDomain().ok()) {
string fog_domain = agent_details->getFogDomain().unpack();
if (host.find(fog_domain) != string::npos) {
origin_is_fog = true;
}
} else {
dbgTrace(D_COMMUNICATION) << "Failed to receive fog domain.";
}
}
string file_name = "";
string url = "";
unsigned int port = 0;
URLParser url_parser;
vector<char> body = {};
string host = "";
bool is_secure = true;
bool origin_is_fog = true;
};
class MessagingDownloaderServer::Impl : Singleton::Provide<I_MessagingDownloader>::From<MessagingDownloaderServer>
{
public:
void
init()
{
i_msg = Singleton::Consume<I_Messaging>::by<MessagingDownloaderServer>();
i_mainloop = Singleton::Consume<I_MainLoop>::by<MessagingDownloaderServer>();
auto rest = Singleton::Consume<I_RestApi>::by<MessagingDownloaderServer>();
rest->addRestCall<MessagingDownloaderReceiver>(RestAction::ADD, "download-file");
string default_downloading_dir = "/tmp/cp_nano_downloader/";
download_dir = getConfigurationWithDefault(
default_downloading_dir,
"Downloader",
"Downloading Directory"
);
NGEN::Filesystem::makeDirRecursive(download_dir);
}
void
fini()
{
i_msg = nullptr;
i_mainloop = nullptr;
}
bool
downloadFile(
const string &file_name,
const string &url,
OnCompleteCB on_complete_func = nullptr,
const unsigned int port = 443
) override
{
dbgTrace(D_COMMUNICATION) << "Handling new download request. URL: " << url << ". File name: " << file_name;
DownloadingInstance req(file_name, url, port);
if (downloading_queue.find(req) != downloading_queue.end()) {
dbgInfo(D_COMMUNICATION) << "Failed to download the file. Similar download request already exists.";
return false;
}
if (!isValidPath(file_name)) {
dbgInfo(D_COMMUNICATION) << "Failed to validate the download path. Path: " << download_dir + file_name;
return false;
}
downloading_queue.insert(req);
i_mainloop->addOneTimeRoutine(
I_MainLoop::RoutineType::RealTime,
[this, req, on_complete_func]() mutable
{
Flags<MessageConnConfig> conn_flags;
if (req.getIsSecure()) conn_flags.setFlag(MessageConnConfig::SECURE_CONN);
if (!req.getIsFogOrigin()) conn_flags.setFlag(MessageConnConfig::EXTERNAL);
auto on_exit = make_scope_exit([this, &req]() { downloading_queue.erase(req); } );
bool response = i_msg->sendObject(
req,
I_Messaging::Method::GET,
req.getHost(),
req.getPort(),
conn_flags,
req.getUrl()
);
if (response) {
dbgTrace(D_COMMUNICATION) << "Successfully received a response from the downloading file host.";
std::ofstream downloaded_file;
downloaded_file.open(download_dir + req.getFileName());
if (!downloaded_file.is_open()) {
dbgInfo(D_COMMUNICATION)
<< "Failed to download file. Error: Failed to open the file "
<< req.getFileName();
Maybe<string> err = genError("Failed to open the file");
on_complete_func(err);
if (i_mainloop != nullptr) i_mainloop->yield(true);
}
auto &res_body = req.getResponse();
downloaded_file.write(res_body.data(), res_body.size());
downloaded_file.close();
dbgInfo(D_COMMUNICATION) << "Successfully downloaded the file. File name: " << req.getFileName();
Maybe<string> filepath = download_dir + req.getFileName();
on_complete_func(filepath);
} else {
dbgInfo(D_COMMUNICATION) << "Failed to download file. File name: " << req.getFileName();
Maybe<string> err = genError("Failed during the downloading process.");
on_complete_func(err);
}
},
"Download file routine for '" + file_name + "'",
false
);
return true;
}
private:
bool
isValidPath(const string &file_name)
{
struct stat info;
string file_to_download = download_dir + file_name;
dbgTrace(D_COMMUNICATION) << "Validating the downloading file path. Path: " << file_to_download;
if (stat(download_dir.c_str(), &info) != 0) {
dbgDebug(D_COMMUNICATION) << "Failed to access the downloading directory";
return false;
}
if (stat(file_to_download.c_str(), &info) == 0) {
dbgDebug(D_COMMUNICATION)
<< "The file with the name '"
<< file_name
<< "' is already exist in the downloading directory";
return false;
}
return true;
}
I_Messaging *i_msg;
I_MainLoop *i_mainloop;
string download_dir;
set<DownloadingInstance> downloading_queue;
};
MessagingDownloaderServer::MessagingDownloaderServer()
:
Component("MessagingDownloaderServer"),
pimpl(make_unique<Impl>())
{}
MessagingDownloaderServer::~MessagingDownloaderServer() {}
void MessagingDownloaderServer::init() { pimpl->init(); }
void MessagingDownloaderServer::fini() { pimpl->fini(); }
void
MessagingDownloaderServer::preload()
{
registerExpectedConfiguration<string>("Downloader", "Downloading Directory");
};

View File

@@ -1,2 +0,0 @@
add_subdirectory(downloader_server_ut)
add_subdirectory(downloader_client_ut)

View File

@@ -1,9 +0,0 @@
link_directories(${BOOST_ROOT}/lib)
include_directories(${CMAKE_SOURCE_DIR}/core/include)
link_directories(${CMAKE_BINARY_DIR}/core/include)
add_unit_test(
downloader_client_ut
"downloader_client_ut.cc"
"singleton;messaging_downloader_client;time_proxy;mainloop;rest;metric;event_is;message;-lboost_context;agent_core_utilities;orchestration_modules;connkey;-lboost_regex;-lboost_filesystem;-lboost_system"
)

View File

@@ -1,113 +0,0 @@
#include "messaging_downloader_client.h"
#include <boost/filesystem.hpp>
#include "environment.h"
#include "singleton.h"
#include "config.h"
#include "config_component.h"
#include "mainloop.h"
#include "cptest.h"
#include "mock/mock_mainloop.h"
#include "mock/mock_messaging.h"
#include "mock/mock_rest_api.h"
#include "mock/mock_agent_details.h"
#include "mock/mock_time_get.h"
using namespace std;
using namespace testing;
class MessagingDownloaderClientTest : public Test
{
public:
MessagingDownloaderClientTest()
{
EXPECT_CALL(
rest,
mockRestCall(RestAction::SHOW, "download-status", _)
).WillOnce(WithArg<2>(Invoke(this, &MessagingDownloaderClientTest::restHandler)));
EXPECT_CALL(rest, mockRestCall(RestAction::ADD, "declare-boolean-variable", _)).WillOnce(Return(true));
Debug::setUnitTestFlag(D_COMMUNICATION, Debug::DebugLevel::TRACE);
Debug::setNewDefaultStdout(&capture_debug);
messaging_downloader.preload();
env.preload();
env.init();
messaging_downloader.init();
}
~MessagingDownloaderClientTest()
{
boost::filesystem::remove_all("/tmp/test_download_dir/");
messaging_downloader.fini();
}
bool
restHandler(const unique_ptr<RestInit> &rest_ptr)
{
rest_handler = rest_ptr->getRest();
return true;
}
unique_ptr<ServerRest> rest_handler;
ostringstream capture_debug;
I_MainLoop::Routine downloading_routine;
MessagingDownloaderClient messaging_downloader;
NiceMock<MockTimeGet> mock_time;
NiceMock<MockAgentDetails> mock_agent_details;
StrictMock<MockMessaging> mock_msg;
StrictMock<MockRestApi> rest;
StrictMock<MockMainLoop> mock_ml;
::Environment env;
ConfigComponent conf;
};
TEST_F(MessagingDownloaderClientTest, do_nothing)
{
}
TEST_F(MessagingDownloaderClientTest, request_download)
{
string file_name = "test_file";
string url = "https://download_test.com/test_download";
Singleton::Consume<I_Environment>::by<MessagingDownloaderClient>()->registerValue<int>("Listening Port", 6464);
stringstream ss;
ss << "{\n \"file_name\": \"" << file_name << "\","
<< "\n \"url\": \"" << url << "\","
<< "\n \"port\": 0,\n \"response_port\": 6464\n}";
EXPECT_CALL(mock_msg, sendMessage(
true,
ss.str(),
I_Messaging::Method::POST,
"127.0.0.1",
8164,
_,
"/add-download-file",
_,
_,
_
)).WillOnce(Return(Maybe<string>(string("{\"uuid\": \"111\", \"status\": true}"))));
bool is_cb_run = false;
bool res = Singleton::Consume<I_MessagingDownloader>::from<MessagingDownloaderClient>()->downloadFile(
file_name,
url,
[&is_cb_run](const Maybe<string>& filepath)
{
is_cb_run = true;
EXPECT_TRUE(filepath.ok());
EXPECT_EQ(filepath.unpack(), "/tmp/test_download_dir/test_file");
}
);
EXPECT_TRUE(res);
stringstream is;
is << "{\"uuid\": \"111\", \"status\": true, \"filepath\": \"/tmp/test_download_dir/test_file\"}";
EXPECT_FALSE(is_cb_run);
rest_handler->performRestCall(is);
EXPECT_TRUE(is_cb_run);
}

View File

@@ -1,9 +0,0 @@
link_directories(${BOOST_ROOT}/lib)
include_directories(${CMAKE_SOURCE_DIR}/core/include)
link_directories(${CMAKE_BINARY_DIR}/core/include)
add_unit_test(
downloader_server_ut
"downloader_server_ut.cc"
"singleton;messaging_downloader_server;time_proxy;mainloop;rest;metric;event_is;message;-lboost_context;agent_core_utilities;orchestration_modules;agent_details;connkey;-lboost_regex;-lboost_filesystem;-lboost_system"
)

View File

@@ -1,304 +0,0 @@
#include "messaging_downloader_server.h"
#include <boost/filesystem.hpp>
#include "environment.h"
#include "singleton.h"
#include "config.h"
#include "config_component.h"
#include "mainloop.h"
#include "cptest.h"
#include "mock/mock_mainloop.h"
#include "mock/mock_messaging.h"
#include "mock/mock_rest_api.h"
#include "mock/mock_agent_details.h"
#include "mock/mock_time_get.h"
using namespace std;
using namespace testing;
class MessagingDownloaderServerTest : public Test
{
public:
MessagingDownloaderServerTest()
{
setConfiguration(string("/tmp/test_download_dir/"), "Downloader", "Downloading Directory");
EXPECT_CALL(
rest,
mockRestCall(RestAction::ADD, "download-file", _)
).WillOnce(WithArg<2>(Invoke(this, &MessagingDownloaderServerTest::restHandler)));
Maybe<string> fog_addr(string("test.fog.com"));
EXPECT_CALL(
mock_agent_details,
getFogDomain()
).WillRepeatedly(Return(fog_addr));
Debug::setUnitTestFlag(D_COMMUNICATION, Debug::DebugLevel::TRACE);
Debug::setNewDefaultStdout(&capture_debug);
messaging_downloader.preload();
messaging_downloader.init();
}
~MessagingDownloaderServerTest()
{
boost::filesystem::remove_all("/tmp/test_download_dir/");
messaging_downloader.fini();
}
bool
restHandler(const unique_ptr<RestInit> &rest_ptr)
{
rest_handler = rest_ptr->getRest();
return true;
}
void
expectRequestSuccess(
string &test_file_name,
string &host,
string &url,
string &uuid,
unsigned int port,
unsigned int response_port,
string &success_msg
)
{
EXPECT_CALL(
mock_ml,
addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, _, false)
).WillOnce(DoAll(SaveArg<1>(&downloading_routine), Return(0)));
EXPECT_CALL(
mock_msg,
sendMessage(true, "", I_Messaging::Method::GET, host, port, _, url, _, _, _)
).WillOnce(Return(Maybe<string>(string("test_body"))));
stringstream expected_response;
expected_response
<< "\n \"status\": true,"
<< "\n \"filepath\": \"/tmp/test_download_dir/" << test_file_name << "\"\n}";
string saved_response;
EXPECT_CALL(mock_msg, sendMessage(
false,
_,
I_Messaging::Method::POST,
"127.0.0.1",
response_port,
_,
"/show-download-status",
_,
_,
_
)).WillOnce(DoAll(SaveArg<1>(&saved_response), Return(Maybe<string>(string()))));
stringstream is;
is << "{\"file_name\": \"" << test_file_name << "\","
<< "\"response_port\": " << response_port << ","
<< "\"url\": \"" << url << "\","
<< "\"port\": " << port << ","
<< "\"uuid\": \"" << uuid << "\"}";
rest_handler->performRestCall(is);
downloading_routine();
EXPECT_THAT(saved_response, HasSubstr(expected_response.str()));
EXPECT_THAT(capture_debug.str(), HasSubstr(success_msg));
}
unique_ptr<ServerRest> rest_handler;
ostringstream capture_debug;
I_MainLoop::Routine downloading_routine;
MessagingDownloaderServer messaging_downloader;
NiceMock<MockTimeGet> mock_time;
StrictMock<MockAgentDetails> mock_agent_details;
StrictMock<MockMessaging> mock_msg;
StrictMock<MockRestApi> rest;
StrictMock<MockMainLoop> mock_ml;
::Environment env;
ConfigComponent conf;
};
TEST_F(MessagingDownloaderServerTest, do_nothing)
{
}
TEST_F(MessagingDownloaderServerTest, add_one_secured_request)
{
string test_file_name = "test_file_name";
string host = "test_host";
string url = "https://test_host/test_url";
string uuid = "111";
string success_msg = "Successfully downloaded the file. File name: " + test_file_name;
unsigned int port = 443;
unsigned int response_port = 123;
expectRequestSuccess(test_file_name, host, url, uuid, port, response_port, success_msg);
}
TEST_F(MessagingDownloaderServerTest, add_one_non_secured_request)
{
string test_file_name = "test_file_name";
string host = "test_host";
string url = "http://test_host/test_url";
string uuid = "111";
string success_msg = "Successfully downloaded the file. File name: " + test_file_name;
unsigned int port = 80;
unsigned int response_port = 123;
expectRequestSuccess(test_file_name, host, url, uuid, port, response_port, success_msg);
}
TEST_F(MessagingDownloaderServerTest, add_multiple_requests)
{
string test_file_name1 = "test_file_name1";
string test_file_name2 = "test_file_name2";
string host = "test_host";
string url = "https://test_host/test_url";
string uuid = "111";
string success_msg1 = "Successfully downloaded the file. File name: " + test_file_name1;
string success_msg2 = "Successfully downloaded the file. File name: " + test_file_name2;
unsigned int port = 443;
unsigned int response_port = 123;
expectRequestSuccess(test_file_name1, host, url, uuid, port, response_port, success_msg1);
expectRequestSuccess(test_file_name2, host, url, uuid, port, response_port, success_msg2);
}
TEST_F(MessagingDownloaderServerTest, add_same_request_twice)
{
string test_file_name = "test_file_name";
string host = "test_host";
string url = "https://test_host/test_url";
string uuid = "111";
unsigned int response_port = 123;
EXPECT_CALL(
mock_ml,
addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, _, false)
).WillOnce(DoAll(SaveArg<1>(&downloading_routine), Return(0)));
EXPECT_CALL(
mock_msg,
sendMessage(true, "", I_Messaging::Method::GET, host, 442, _, url, _, _, _)
).WillOnce(Return(Maybe<string>(string("test_body"))));
stringstream expected_response;
expected_response
<< "\n \"status\": true,"
<< "\n \"filepath\": \"/tmp/test_download_dir/" << test_file_name << "\"\n}";
string saved_response;
EXPECT_CALL(mock_msg, sendMessage(
false,
_,
I_Messaging::Method::POST,
"127.0.0.1",
response_port,
_,
"/show-download-status",
_,
_,
_
)).WillOnce(DoAll(SaveArg<1>(&saved_response), Return(Maybe<string>(string()))));
stringstream is;
is
<< "{\"file_name\": \"" << test_file_name << "\","
<< "\"response_port\": " << response_port << ","
<< "\"uuid\": \"" << uuid << "\","
<< "\"port\": 442,"
<< "\"url\": \"" << url << "\"}";
rest_handler->performRestCall(is);
rest_handler->doCall();
downloading_routine();
EXPECT_THAT(saved_response, HasSubstr(expected_response.str()));
EXPECT_THAT(
capture_debug.str(),
HasSubstr("Failed to download the file. Similar download request already exists.")
);
}
TEST_F(MessagingDownloaderServerTest, add_request_that_fails)
{
string test_file_name = "test_file_name";
string host = "test_host";
string url = "https://test_host/test_url";
string uuid = "111";
unsigned int response_port = 123;
unsigned int additional_port_test = 123;
Maybe<string> err = genError("no");
EXPECT_CALL(
mock_ml,
addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, _, false)
).WillOnce(DoAll(SaveArg<1>(&downloading_routine), Return(0)));
EXPECT_CALL(
mock_msg,
sendMessage(true, "", I_Messaging::Method::GET, host, additional_port_test, _, url, _, _, _)
).WillOnce(Return(err));
stringstream expected_response;
expected_response
<< "\n \"status\": false,"
<< "\n \"error\": \"Failed during the downloading process.\"\n}";
string saved_response;
EXPECT_CALL(mock_msg, sendMessage(
false,
_,
I_Messaging::Method::POST,
"127.0.0.1",
response_port,
_,
"/show-download-status",
_,
_,
_
)).WillOnce(DoAll(SaveArg<1>(&saved_response), Return(Maybe<string>(string()))));
stringstream is;
is
<< "{\"file_name\": \"" << test_file_name << "\","
<< "\"response_port\": " << response_port << ","
<< "\"url\": \"" << url << "\","
<< "\"port\": " << additional_port_test << ","
<< "\"uuid\": \"" << uuid << "\"}";
rest_handler->performRestCall(is);
downloading_routine();
EXPECT_THAT(saved_response, HasSubstr(expected_response.str()));
EXPECT_THAT(capture_debug.str(), HasSubstr("Failed to download file. File name: test_file_name"));
}
TEST_F(MessagingDownloaderServerTest, download_with_same_filename)
{
string test_file_name = "test_file_name";
string host = "test_host";
string url1 = "https://test_host/test_url1";
string url2 = "https://test_host/test_url2";
string uuid = "111";
unsigned int port = 443;
string success_msg = "Successfully downloaded the file. File name: " + test_file_name;
unsigned int response_port = 123;
expectRequestSuccess(test_file_name, host, url1, uuid, port, response_port, success_msg);
stringstream is;
is
<< "{\"file_name\": \"" << test_file_name << "\","
<< "\"response_port\": " << response_port << ","
<< "\"port\": " << port << ","
<< "\"url\": \"" << url2 << "\"}";
rest_handler->performRestCall(is);
EXPECT_THAT(
capture_debug.str(),
HasSubstr("The file with the name 'test_file_name' is already exist in the downloading directory")
);
}

View File

@@ -278,7 +278,8 @@ Layer7AccessControl::Impl::generateLog(const string &source_ip, const Intelligen
<< genLogIPField("destinationIP", HttpTransactionData::listening_ip_ctx)
<< LogField("securityAction", security_action)
<< LogField("sourceIP", source_ip)
<< LogField("externalVendorName", "crowdsec")
<< LogField("externalVendorName", "CrowdSec")
<< LogField("waapIncidentType", "CrowdSec")
<< ip_reputation.getCrowdsecEventId()
<< ip_reputation.getType()
<< ip_reputation.getOrigin()

View File

@@ -7,6 +7,7 @@
#include "mock/mock_http_manager.h"
#include "mock/mock_logging.h"
#include "mock/mock_messaging.h"
#include "mock/mock_rest_api.h"
#include "intelligence_comp_v2.h"
#include "agent_details.h"
@@ -27,6 +28,7 @@ public:
EXPECT_CALL(mock_time, getMonotonicTime()).WillRepeatedly(Return(chrono::seconds(60)));
EXPECT_CALL(mock_ml, doesRoutineExist(_)).WillRepeatedly(Return(true));
EXPECT_CALL(mock_ml, stop(_)).WillRepeatedly(Return());
EXPECT_CALL(mock_ml, addRecurringRoutine(_, _, _, "Sending intelligence invalidation", _));
env.preload();
env.init();
config.preload();
@@ -57,6 +59,7 @@ public:
StrictMock<MockTimeGet> mock_time;
StrictMock<MockMainLoop> mock_ml;
StrictMock<MockMessaging> messaging_mock;
NiceMock<MockRestApi> mock_rest;
AgentDetails agent_details;
IntelligenceComponentV2 intelligence_comp;
Context ctx;
@@ -243,7 +246,8 @@ Layer7AccessControlTest::verifyReport(
EXPECT_THAT(log, HasSubstr("\"httpMethod\": \"POST\""));
EXPECT_THAT(log, HasSubstr("\"ipProtocol\": \"http\""));
EXPECT_THAT(log, HasSubstr("\"destinationIP\": \"5.6.7.8\""));
EXPECT_THAT(log, HasSubstr("\"externalVendorName\": \"crowdsec\""));
EXPECT_THAT(log, HasSubstr("\"externalVendorName\": \"CrowdSec\""));
EXPECT_THAT(log, HasSubstr("\"waapIncidentType\": \"CrowdSec\""));
EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendationId\": 2253734"));
EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendedAction\": \"ban\""));
EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendationOrigin\": \"cscli\""));

View File

@@ -70,6 +70,14 @@ checkHasSDWan(const string &command_output)
return genError("Current host does not have SDWAN capability");
}
Maybe<string>
checkCanUpdateSDWanData(const string &command_output)
{
if (command_output == "true" || command_output == "false") return command_output;
return string("true");
}
Maybe<string>
getMgmtObjType(const string &command_output)
{
@@ -157,6 +165,14 @@ getGWVersion(shared_ptr<istream> file_stream)
return getMgmtObjAttr(file_stream, "svn_version_name ");
}
Maybe<string>
checkIfSdwanRunning(const string &command_output)
{
if (command_output == "true" || command_output == "false") return command_output;
return genError("Could not determine if sd-wan is running or not");
}
Maybe<string>
getSmbObjectName(const string &command_output)
{

View File

@@ -31,6 +31,11 @@
#if defined(gaia) || defined(smb)
SHELL_CMD_HANDLER("cpProductIntegrationMgmtObjectType", "cpprod_util CPPROD_IsMgmtMachine", getMgmtObjType)
SHELL_CMD_HANDLER("hasSDWan", "[ -f $FWDIR/bin/sdwan_steering ] && echo '1' || echo '0'", checkHasSDWan)
SHELL_CMD_HANDLER("canUpdateSDWanData", "cpsdwan get_data | jq -r .can_update_sdwan_data", checkCanUpdateSDWanData)
SHELL_CMD_HANDLER(
"isSdwanRunning",
"[ -v $(pidof cp-nano-sdwan) ] && echo 'false' || echo 'true'",
checkIfSdwanRunning)
#endif //gaia || smb
#if defined(gaia)

View File

@@ -14,7 +14,6 @@
#ifndef __GET_STATUS_RES_H__
#define __GET_STATUS_RES_H__
#include "i_messaging_downloader.h"
#include "i_messaging.h"
#include "i_mainloop.h"
#include "i_shell_cmd.h"

View File

@@ -1,39 +0,0 @@
// 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 __MOCK_MESSAGING_DOWNLOADER_H__
#define __MOCK_MESSAGING_DOWNLOADER_H__
#include "cptest.h"
#include <string>
#include "i_messaging_downloader.h"
class MockMessagingDownloader
:
public Singleton::Provide<I_MessagingDownloader>::From<MockProvider<I_MessagingDownloader>>
{
public:
MOCK_METHOD4(
downloadFile,
bool(
const std::string &,
const std::string &,
OnCompleteCB,
const unsigned int
)
);
};
#endif // __MOCK_MESSAGING_DOWNLOADER_H__

View File

@@ -26,6 +26,10 @@ class MockServiceController :
public:
MOCK_METHOD0(refreshPendingServices, void());
MOCK_METHOD0(mockMoveChangedPolicies, std::set<std::string>());
std::set<std::string> tmp;
std::set<std::string> && moveChangedPolicies() override { tmp = mockMoveChangedPolicies(); return std::move(tmp); }
MOCK_METHOD0(doesFailedServicesExist, bool());
MOCK_METHOD0(clearFailedServices, void());

View File

@@ -740,6 +740,7 @@ TEST_F(ManifestControllerTest, selfUpdateWithOldCopyWithError)
orch_service_name;
EXPECT_CALL(mock_orchestration_tools, doesFileExist(path)).WillOnce(Return(false)).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, copyFile(path, path + backup_ext + temp_ext)).WillOnce(Return(false));
EXPECT_CALL(mock_details_resolver, getHostname()).WillOnce(Return(hostname));
EXPECT_FALSE(i_manifest_controller->updateManifest(file_name));
}

View File

@@ -145,23 +145,21 @@ ManifestHandler::downloadPackages(
}
}
downloaded_packages.clear();
auto agent_details = Singleton::Consume<I_AgentDetails>::by<ManifestHandler>();
auto hostname = Singleton::Consume<I_DetailsResolver>::by<ManifestHandler>()->getHostname();
string err_hostname = (hostname.ok() ? "on host '" + *hostname : "'" + agent_details->getAgentId()) + "'";
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 +
"Critical Error: Agent/Gateway was not fully deployed " +
err_hostname +
" 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.";
"Warning: Agent/Gateway " +
err_hostname +
" software update failed. Agent is running previous software. Contact Check Point support.";
}
auto orchestration_status = Singleton::Consume<I_OrchestrationStatus>::by<ManifestHandler>();
@@ -221,11 +219,13 @@ ManifestHandler::installPackages(
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>();
auto details = Singleton::Consume<I_AgentDetails>::by<ManifestHandler>();
auto hostname = Singleton::Consume<I_DetailsResolver>::by<ManifestHandler>()->getHostname();
string err_hostname = (hostname.ok() ? "on host '" + *hostname : "'" + details->getAgentId()) + "'";
string install_error =
"Warning: Agent/Gateway '" +
agent_details->getAgentId() +
"' software update failed. Agent is running previous software. Contact Check Point support.";
"Warning: Agent/Gateway " +
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,
@@ -278,23 +278,20 @@ ManifestHandler::installPackages(
}
if (!current_result) {
auto agent_details = Singleton::Consume<I_AgentDetails>::by<ManifestHandler>();
auto hostname = Singleton::Consume<I_DetailsResolver>::by<ManifestHandler>()->getHostname();
string err_hostname = (hostname.ok() ? "on host '" + *hostname : "'" +agent_details->getAgentId()) + "'";
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 +
"Critical Error: Agent/Gateway was not fully deployed " +
err_hostname +
" 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.";
"Warning: Agent/Gateway " +
err_hostname +
" 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;

View File

@@ -41,6 +41,7 @@
#include "tenant_profile_pair.h"
#include "env_details.h"
#include "hybrid_communication.h"
#include "agent_core_utilities.h"
using namespace std;
using namespace chrono;
@@ -48,6 +49,14 @@ using namespace ReportIS;
USE_DEBUG_FLAG(D_ORCHESTRATOR);
static const string ls_prefix = "ls ";
static const string extract_tenant_profile_suffix =
"| grep tenant "
"| cut -d '_' -f 2,4 "
"| sort --unique "
"| awk -F '_' '{ printf \"%s %s \",$1,$2 }'";
class HealthCheckStatusListener : public Listener<HealthCheckStatusEvent>
{
public:
@@ -193,6 +202,7 @@ public:
ReportIS::Audience::INTERNAL
);
hybrid_mode_metric.registerListener();
loadExistingTenantsFromConfDir();
}
void
@@ -237,7 +247,9 @@ private:
}
policy_version = service_controller->getPolicyVersion();
Singleton::Consume<I_OrchestrationStatus>::by<OrchestrationComp>()->setPolicyVersion(policy_version);
if (!policy_version.empty()) {
Singleton::Consume<I_OrchestrationStatus>::by<OrchestrationComp>()->setPolicyVersion(policy_version);
}
} else {
dbgDebug(D_ORCHESTRATOR) << "Orchestration is running for the first time";
enforce_policy_flag = true;
@@ -277,6 +289,59 @@ private:
return authentication_res;
}
void
loadExistingTenantsFromConfDir()
{
dbgTrace(D_ORCHESTRATOR) << "Load existing tenants and profiles from the configuration folder";
string global_conf_dir = getConfigurationWithDefault<string>(
getFilesystemPathConfig()+ "/conf/",
"orchestration",
"Conf dir"
);
string shell_cmd_string = ls_prefix + global_conf_dir + extract_tenant_profile_suffix;
auto shell = Singleton::Consume<I_ShellCmd>::by<OrchestrationComp>();
Maybe<string> output_res = shell->getExecOutput(shell_cmd_string);
if (!output_res.ok()) {
dbgWarning(D_ORCHESTRATOR)
<< "Failed to load existing tenants from configuration folder: " + output_res.getErr();
return;
}
auto tenant_manager = Singleton::Consume<I_TenantManager>::by<OrchestrationComp>();
stringstream ss(output_res.unpack());
string tenant_id;
string profile_id;
while (!ss.eof() && getline(ss, tenant_id, ' ') && !ss.eof() && getline(ss, profile_id, ' ')) {
dbgTrace(D_ORCHESTRATOR) << "Add existing tenant_" + tenant_id + "_profile_" + profile_id;
tenant_manager->addActiveTenantAndProfile(tenant_id, profile_id);
}
}
void
deleteInactiveTenantProfileFiles(const string &tenant_id, const string &profile_id)
{
string global_conf_dir = getConfigurationWithDefault<string>(
getFilesystemPathConfig()+ "/conf/",
"orchestration",
"Conf dir"
);
string tenant_and_profile_suffix = "tenant_" + tenant_id + "_profile_" + profile_id;
string virtual_policy_dir = global_conf_dir + tenant_and_profile_suffix;
dbgTrace(D_ORCHESTRATOR) << "Delete virtual policy folder : " << virtual_policy_dir;
if (!NGEN::Filesystem::deleteDirectory(virtual_policy_dir, true)) {
dbgWarning(D_ORCHESTRATOR) << "Failed to delete virtual policy folder : " << virtual_policy_dir;
}
string settings_file_path = virtual_policy_dir + "_settings.json";
dbgTrace(D_ORCHESTRATOR) << "Delete settings file " << settings_file_path;
if (!NGEN::Filesystem::deleteFile(settings_file_path)) {
dbgWarning(D_ORCHESTRATOR) << "Failed to delete virtual policy settings file : " << settings_file_path;
}
}
Maybe<OrchestrationPolicy>
loadOrchestrationPolicy()
{
@@ -404,33 +469,30 @@ private:
dbgInfo(D_ORCHESTRATOR) << "There is a new manifest file.";
GetResourceFile resource_file(GetResourceFile::ResourceFileType::MANIFEST);
Maybe<string> new_manifest_file =
Singleton::Consume<I_Downloader>::by<OrchestrationComp>()->downloadFileFromFog(
orch_manifest.unpack(),
I_OrchestrationTools::SELECTED_CHECKSUM_TYPE,
resource_file
);
Singleton::Consume<I_Downloader>::by<OrchestrationComp>()->downloadFileFromFog(
orch_manifest.unpack(),
I_OrchestrationTools::SELECTED_CHECKSUM_TYPE,
resource_file
);
auto orch_status = Singleton::Consume<I_OrchestrationStatus>::by<OrchestrationComp>();
auto service_controller = Singleton::Consume<I_ServiceController>::by<OrchestrationComp>();
auto agent_details = Singleton::Consume<I_AgentDetails>::by<OrchestrationComp>();
static int service_to_port_size = service_controller->getServiceToPortMap().size();
auto hostname = Singleton::Consume<I_DetailsResolver>::by<ManifestHandler>()->getHostname();
string err_hostname = (hostname.ok() ? "on host '" + *hostname : "'" + agent_details->getAgentId()) + "'";
if (!new_manifest_file.ok()) {
string install_error;
if (!service_to_port_size) {
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 +
"Critical Error: Agent/Gateway was not fully deployed " +
err_hostname +
" and is not enforcing a security policy. Retry installation or contact Check Point support.";
} else {
install_error =
"Warning: Agent/Gateway '" +
agent_details->getAgentId() +
"' software update failed. Agent is running previous software. Contact Check Point support.";
"Warning: Agent/Gateway " +
err_hostname +
" software update failed. Agent is running previous software. Contact Check Point support.";
}
dbgTrace(D_ORCHESTRATOR)
<< "Manifest failed to be updated. Error: "
@@ -455,9 +517,9 @@ private:
auto manifest_controller = Singleton::Consume<I_ManifestController>::by<OrchestrationComp>();
if (!manifest_controller->updateManifest(new_manifest_file.unpack())) {
string install_error =
"Warning: Agent/Gateway '" +
agent_details->getAgentId() +
"' software update failed. Agent is running previous software. Contact Check Point support.";
"Warning: Agent/Gateway " +
err_hostname +
" software update failed. Agent is running previous software. Contact Check Point support.";
string current_error = orch_status->getManifestError();
if (current_error.find("Gateway was not fully deployed") == string::npos) {
orch_status->setFieldStatus(
@@ -499,9 +561,9 @@ private:
}
string manifest_success_notification_message(
"Agent/Gateway '" +
agent_details->getAgentId() +
"' software update succeeded. Agent is running latest software."
"Agent/Gateway " +
err_hostname +
" software update succeeded. Agent is running latest software."
);
LogGen manifest_success_notification(
manifest_success_notification_message,
@@ -517,7 +579,6 @@ private:
return Maybe<void>();
}
// LCOV_EXCL_START Reason: future changes will be done
bool
updateServiceConfigurationFromBackup()
{
@@ -565,7 +626,6 @@ private:
dbgWarning (D_ORCHESTRATOR) << "Failed to load Orchestration policy.";
return false;
}
// LCOV_EXCL_STOP
string
updatePolicyAndFogAddress(const OrchestrationPolicy &orchestration_policy)
@@ -582,7 +642,9 @@ private:
auto service_controller = Singleton::Consume<I_ServiceController>::by<OrchestrationComp>();
string new_policy_version = service_controller->getPolicyVersion();
Singleton::Consume<I_OrchestrationStatus>::by<OrchestrationComp>()->setPolicyVersion(new_policy_version);
if (!new_policy_version.empty()) {
Singleton::Consume<I_OrchestrationStatus>::by<OrchestrationComp>()->setPolicyVersion(new_policy_version);
}
auto update_communication = Singleton::Consume<I_UpdateCommunication>::by<OrchestrationComp>();
auto path_policy_version = update_communication->sendPolicyVersion(new_policy_version);
if (!path_policy_version.ok()) {
@@ -617,7 +679,7 @@ private:
"last fog policy file extension"
);
if (!orchestration_tools->copyFile(new_policy_file.unpack(), conf_path + last_ext)) {
dbgWarning(D_ORCHESTRATOR) << "Failed to copy a new policy file to " << conf_path + last_ext;
dbgWarning(D_ORCHESTRATOR) << "Failed to copy a new policy file to " << conf_path + last_ext;
}
// Calculate the changes between the existing policy to the new one.
@@ -648,6 +710,11 @@ private:
"Settings file path"
);
set<string> changed_policy_files = service_controller->moveChangedPolicies();
for (const string &changed_policy_file : changed_policy_files) {
orchestration_tools->writeFile("{}\n", changed_policy_file);
}
service_controller->updateServiceConfiguration(policy_file, setting_file, data_updates);
LogGen(
error_str,
@@ -661,6 +728,7 @@ private:
return genError(error_str);
}
service_controller->moveChangedPolicies();
// Reload the orchestration policy, in case of the policy updated
auto orchestration_policy = loadDefaultOrchestrationPolicy();
@@ -672,8 +740,6 @@ private:
if (new_policy_version.empty()) {
return genError("Failed to load Orchestration new policy file.");
}
reloadConfiguration();
if (getProfileAgentSettingWithDefault<bool>(false, "agent.config.orchestration.reportAgentDetail")) {
service_controller->clearFailedServices();
reportAgentDetailsMetaData();
@@ -1021,12 +1087,13 @@ private:
vector<string> data_updates;
update_results[OrchestrationStatusConfigType::DATA] = handleDataUpdate(orch_data, data_updates);
update_results[OrchestrationStatusConfigType::POLICY] = handlePolicyUpdate(
orch_policy,
settings_path,
data_updates
);
if (!orch_manifest.ok() && orch_policy.ok()) {
update_results[OrchestrationStatusConfigType::POLICY] = handlePolicyUpdate(
orch_policy,
settings_path,
data_updates
);
}
if (!orch_policy.ok() && (data_updates.size() > 0 || settings_path != "")) {
auto service_controller = Singleton::Consume<I_ServiceController>::by<OrchestrationComp>();
bool res = service_controller->updateServiceConfiguration(
@@ -1046,22 +1113,19 @@ private:
string recommended_fix;
string msg;
bool is_deploy_error = current_error.find("Critical") != string::npos;
auto hostname = Singleton::Consume<I_DetailsResolver>::by<ManifestHandler>()->getHostname();
string err_hostname = (hostname.ok() ? "on host '" + *hostname : "'" + agent_details->getAgentId()) + "'";
if (is_deploy_error) {
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() + "'";
}
msg =
"Agent/Gateway was not fully deployed" +
error_hostname_addition +
"Agent/Gateway was not fully deployed " +
err_hostname +
" and is not enforcing a security policy.";
recommended_fix = "Retry installation or contact Check Point support.";
} else if (current_error.find("Warning") != string::npos) {
msg =
"Agent/Gateway '" +
agent_details->getAgentId() +
"' software update failed. Agent is running previous software.";
"Agent/Gateway " +
err_hostname +
" software update failed. Agent is running previous software.";
recommended_fix = "Contact Check Point support.";
}
if (!msg.empty() && !recommended_fix.empty()) {
@@ -1114,7 +1178,11 @@ private:
bool is_empty = true;
GetResourceFile resource_v_policy_file(GetResourceFile::ResourceFileType::VIRTUAL_POLICY);
I_Downloader *downloader = Singleton::Consume<I_Downloader>::by<OrchestrationComp>();
auto tenant_manager = Singleton::Consume<I_TenantManager>::by<OrchestrationComp>();
map<string, set<string>> profiles_to_be_deleted =
tenant_manager->fetchAndUpdateActiveTenantsAndProfiles(false);
for (const auto &tenant: *updated_policy_tenants) {
profiles_to_be_deleted[tenant.getTenantID()].erase(tenant.getProfileID());
if (!tenant.getVersion().empty()) {
is_empty = false;
@@ -1127,7 +1195,6 @@ private:
<< tenant.getTenantID()
<< " Profile: "
<< profile_to_use;
auto tenant_manager = Singleton::Consume<I_TenantManager>::by<OrchestrationComp>();
tenant_manager->addActiveTenantAndProfile(tenant.getTenantID(), profile_to_use);
resource_v_policy_file.addTenant(
@@ -1204,6 +1271,22 @@ private:
}
}
for (const auto &tenant_profile_set : profiles_to_be_deleted) {
auto tenant_id = tenant_profile_set.first;
for (const auto &profile_id: tenant_profile_set.second) {
dbgTrace(D_ORCHESTRATOR)
<< "Delete configuration files for inactive profile: "
<< "Tenant ID: "
<< tenant_id
<< ", Profile ID: "
<< profile_id;
tenant_manager->deactivateTenant(tenant_id, profile_id);
deleteInactiveTenantProfileFiles(tenant_id, profile_id);
}
}
clearOldTenants();
for (auto it = sorted_files.begin(); it != sorted_files.end(); it++) {
const auto &downloaded_files = *it;
auto files = downloaded_files.second;
@@ -1574,6 +1657,9 @@ private:
auto server = TagAndEnumManagement::convertStringToTag(server_name);
if (server.ok()) tags.insert(*server);
if (getAttribute("no-setting", "CROWDSEC_ENABLED") == "true") tags.insert(Tags::CROWDSEC);
if (getAttribute("no-setting", "PLAYGROUND") == "true") tags.insert(Tags::PLAYGROUND);
Report registration_report(
"Local Agent Data",
Singleton::Consume<I_TimeGet>::by<OrchestrationComp>()->getWalltime(),

View File

@@ -17,7 +17,6 @@
#include "mock/mock_time_get.h"
#include "mock/mock_rest_api.h"
#include "mock/mock_tenant_manager.h"
#include "mock/mock_messaging_downloader.h"
#include "config.h"
#include "config_component.h"
#include "agent_details.h"
@@ -35,7 +34,6 @@ public:
mockRestCall(RestAction::SET, "new-configuration", _)
).WillOnce(WithArg<2>(Invoke(this, &OrchestrationMultitenancyTest::setNewConfiguration)));
EXPECT_CALL(tenant_manager, getTimeoutVal()).WillOnce(Return(chrono::microseconds(0)));
EXPECT_CALL(
mock_ml,
addRecurringRoutine(I_MainLoop::RoutineType::System, _, _, _, _)
@@ -76,6 +74,17 @@ public:
).WillOnce(Return(true));
doEncrypt();
EXPECT_CALL(
mock_shell_cmd,
getExecOutput(
"ls /etc/cp/conf/"
"| grep tenant "
"| cut -d '_' -f 2,4 "
"| sort --unique "
"| awk -F '_' '{ printf \"%s %s \",$1,$2 }'",
_,
_
)).WillOnce(Return(Maybe<string>(string(""))));
orchestration_comp.init();
}
@@ -173,7 +182,6 @@ public:
StrictMock<MockServiceController> mock_service_controller;
StrictMock<MockManifestController> mock_manifest_controller;
StrictMock<MockUpdateCommunication> mock_update_communication;
StrictMock<MockMessagingDownloader> mock_messaging_downloader;
StrictMock<MockTenantManager> tenant_manager;
NiceMock<MockOrchestrationStatus> mock_status;
@@ -225,6 +233,10 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource)
string first_policy_version = "";
string host_url = "https://" + host_address + "/";
stringstream debug_output;
Debug::setNewDefaultStdout(&debug_output);
Debug::setUnitTestFlag(D_ORCHESTRATOR, Debug::DebugLevel::TRACE);
EXPECT_CALL(
rest,
mockRestCall(RestAction::ADD, "proxy", _)
@@ -266,7 +278,13 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource)
.Times(2).WillRepeatedly(ReturnRef(first_policy_version));
set<string> active_tenants = { "1236", "1235" };
map<string, set<string>> old_tenant_profile_set;
set<string> old_profiles = { "123123" };
old_tenant_profile_set["321321"] = old_profiles;
EXPECT_CALL(tenant_manager, fetchActiveTenants()).WillOnce(Return(active_tenants));
EXPECT_CALL(tenant_manager, fetchAndUpdateActiveTenantsAndProfiles(false))
.WillOnce(Return(old_tenant_profile_set));
EXPECT_CALL(tenant_manager, deactivateTenant("321321", "123123")).Times(1);
EXPECT_CALL(tenant_manager, addActiveTenantAndProfile("1235", "2311"));
EXPECT_CALL(tenant_manager, addActiveTenantAndProfile("1236", "2611"));
@@ -479,4 +497,9 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource)
try {
runRoutine();
} catch (const invalid_argument& e) {}
string debug_str_folder = "Delete virtual policy folder : /etc/cp/conf/tenant_321321_profile_123123";
string debug_str_settings = "Delete settings file /etc/cp/conf/tenant_321321_profile_123123_settings.json";
EXPECT_THAT(debug_output.str(), HasSubstr(debug_str_folder));
EXPECT_THAT(debug_output.str(), HasSubstr(debug_str_settings));
Debug::setNewDefaultStdout(&cout);
}

View File

@@ -16,7 +16,6 @@
#include "mock/mock_messaging.h"
#include "mock/mock_time_get.h"
#include "mock/mock_rest_api.h"
#include "mock/mock_messaging_downloader.h"
#include "mock/mock_tenant_manager.h"
#include "config.h"
#include "config_component.h"
@@ -95,6 +94,17 @@ public:
)).WillRepeatedly(DoAll(SaveArg<1>(&message_body), Return(Maybe<string>(string("")))));
doEncrypt();
EXPECT_CALL(
mock_shell_cmd,
getExecOutput(
"ls /etc/cp/conf/"
"| grep tenant "
"| cut -d '_' -f 2,4 "
"| sort --unique "
"| awk -F '_' '{ printf \"%s %s \",$1,$2 }'",
_,
_
)).WillOnce(Return(Maybe<string>(string(""))));
orchestration_comp.init();
}
@@ -138,6 +148,7 @@ public:
EXPECT_CALL(mock_details_resolver, isVersionEqualOrAboveR8110()).WillRepeatedly(Return(false));
EXPECT_CALL(mock_details_resolver, parseNginxMetadata()).WillRepeatedly(Return(no_nginx));
EXPECT_CALL(mock_details_resolver, getAgentVersion()).WillRepeatedly(Return("1.1.1"));
EXPECT_CALL(mock_details_resolver, getHostname()).WillRepeatedly(Return(string("hostname")));
map<string, string> resolved_mgmt_details({{"kernel_version", "4.4.0-87-generic"}});
EXPECT_CALL(mock_details_resolver, getResolvedDetails()).WillRepeatedly(Return(resolved_mgmt_details));
@@ -277,7 +288,6 @@ public:
unique_ptr<ServerRest> rest_status;
StrictMock<MockOrchestrationTools> mock_orchestration_tools;
StrictMock<MockDownloader> mock_downloader;
StrictMock<MockMessagingDownloader> mock_messaging_downloader;
StrictMock<MockShellCmd> mock_shell_cmd;
StrictMock<MockMessaging> mock_message;
StrictMock<MockRestApi> rest;
@@ -538,6 +548,222 @@ TEST_F(OrchestrationTest, check_sending_registration_data)
EXPECT_THAT(message_body, HasSubstr("\"NGINX Server\""));
}
TEST_F(OrchestrationTest, orchestrationPolicyUpdatRollback)
{
Debug::setUnitTestFlag(D_CONFIG, Debug::DebugLevel::TRACE);
waitForRestCall();
preload();
EXPECT_CALL(
mock_ml,
addOneTimeRoutine(I_MainLoop::RoutineType::Offline, _, "Send policy update report", _)
).WillOnce(Return(1));
EXPECT_CALL(
rest,
mockRestCall(RestAction::ADD, "proxy", _)
).WillOnce(WithArg<2>(Invoke(this, &OrchestrationTest::restHandler)));
EXPECT_CALL(mock_status, setFogAddress(host_url)).Times(2);
string config_json =
"{\n"
"\"agentSettings\": [{\n"
"\"key\": \"agent.config.orchestration.reportAgentDetail\",\n"
"\"id\": \"id1\",\n"
"\"value\": \"true\"\n"
"}]\n"
"}\n";
istringstream ss(config_json);
Singleton::Consume<Config::I_Config>::from(config_comp)->loadConfiguration(ss);
init();
// All duplicates should be removed in INXT-35947
string orchestration_policy_file_path = "/etc/cp/conf/orchestration/orchestration.policy";
string manifest_file_path = "/etc/cp/conf/manifest.json";
string setting_file_path = "/etc/cp/conf/settings.json";
string policy_file_path = "/etc/cp/conf/policy.json";
string policy_file_path_bk = "/etc/cp/conf/policy.json.bk";
string last_policy_file_path = "/etc/cp/conf/policy.json.last";
string data_file_path = "/etc/cp/conf/data.json";
string host_address = "1.2.3.5";
string new_host_address = "6.2.3.5";
string new_host_url = "https://" + new_host_address + "/test/";
string new_policy_path = "/some-path";
string manifest_checksum = "manifest";
string policy_checksum = "policy";
string settings_checksum = "settings";
string data_checksum = "data";
string new_policy_checksum= "111111";
string second_val = "12";
string third_val = "13";
Maybe<string> policy_response(
string(
"{\n"
" \"fog-address\": \"" + host_url + "\",\n"
" \"agent-type\": \"test\",\n"
" \"pulling-interval\": 25,\n"
" \"error-pulling-interval\": 15\n"
"}"
)
);
Maybe<string> new_policy_response(
string(
"{\n"
" \"fog-address\": \"" + new_host_url + "\",\n"
" \"agent-type\": \"test\",\n"
" \"pulling-interval\": 25,\n"
" \"error-pulling-interval\": 15\n"
"}"
)
);
set<string> expected_changed_policies = {};
EXPECT_CALL(mock_service_controller, mockMoveChangedPolicies()).WillOnce(Return(expected_changed_policies));
EXPECT_CALL(mock_status, setFogAddress(new_host_url));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).WillOnce(Return(true));
// Rollback related test: The readFile function is called 3 times:
// 1. Read the current policy file
// 2. Read the new policy file - The one that should fail
// 3. Read the current policy file again - The one that should be restored
EXPECT_CALL(mock_orchestration_tools, readFile(orchestration_policy_file_path))
.WillOnce(Return(policy_response))
.WillOnce(Return(new_policy_response))
.WillOnce(Return(policy_response));
EXPECT_CALL(mock_orchestration_tools, copyFile(new_policy_path, policy_file_path + ".last"))
.WillOnce(Return(true));
EXPECT_CALL(mock_message, setActiveFog(host_address, 443, true, MessageTypeTag::GENERIC))
.Times(2).WillRepeatedly(Return(true));
EXPECT_CALL(mock_update_communication, setAddressExtenesion("")).Times(2);
EXPECT_CALL(mock_update_communication, authenticateAgent()).WillOnce(Return(Maybe<void>()));
expectDetailsResolver();
EXPECT_CALL(mock_manifest_controller, loadAfterSelfUpdate()).WillOnce(Return(false));
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::SHA256, manifest_file_path))
.WillOnce(Return(manifest_checksum));
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::SHA256, setting_file_path))
.WillOnce(Return(settings_checksum));
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::SHA256, policy_file_path))
.WillOnce(Return(policy_checksum));
EXPECT_CALL(mock_orchestration_tools, calculateChecksum(Package::ChecksumTypes::SHA256, data_file_path))
.WillOnce(Return(data_checksum));
// Rollback related test: After failing to update the policy file, the policy version should be restored
EXPECT_CALL(mock_service_controller, getPolicyVersion())
.Times(5)
.WillOnce(ReturnRef(first_policy_version))
.WillOnce(ReturnRef(first_policy_version))
.WillOnce(ReturnRef(second_val))
.WillOnce(ReturnRef(third_val))
.WillOnce(ReturnRef(second_val)
);
EXPECT_CALL(mock_status, setPolicyVersion(third_val));
EXPECT_CALL(mock_status, setPolicyVersion(second_val));
EXPECT_CALL(mock_update_communication, sendPolicyVersion("13")).Times(1).WillOnce(Return(Maybe<void>()));
// Rollback related test: The old policy version 12 is restored
EXPECT_CALL(mock_update_communication, sendPolicyVersion("12")).Times(1).WillOnce(Return(Maybe<void>()));
EXPECT_CALL(mock_update_communication, getUpdate(_)).WillOnce(
Invoke(
[&](CheckUpdateRequest &req)
{
EXPECT_THAT(req.getPolicy(), IsValue(policy_checksum));
EXPECT_THAT(req.getSettings(), IsValue(settings_checksum));
EXPECT_THAT(req.getManifest(), IsValue(manifest_checksum));
EXPECT_THAT(req.getData(), IsValue(data_checksum));
req = CheckUpdateRequest("", new_policy_checksum, "", "", "", "");
return Maybe<void>();
}
)
);
GetResourceFile policy_file(GetResourceFile::ResourceFileType::POLICY);
EXPECT_CALL(
mock_downloader,
downloadFileFromFog(new_policy_checksum, Package::ChecksumTypes::SHA256, policy_file)
).WillOnce(Return(Maybe<std::string>(new_policy_path)));
vector<string> expected_data_types = {};
EXPECT_CALL(
mock_service_controller,
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _)
).WillOnce(Return(true));
EXPECT_CALL(
mock_service_controller,
updateServiceConfiguration(new_policy_path, "", expected_data_types, "", "", _)
).WillOnce(Return(true));
EXPECT_CALL(
mock_message,
setActiveFog(new_host_address, 443, true, MessageTypeTag::GENERIC)
).WillOnce(Return(true));
EXPECT_CALL(mock_update_communication, setAddressExtenesion("/test"));
EXPECT_CALL(mock_status, setLastUpdateAttempt());
EXPECT_CALL(
mock_status,
setFieldStatus(OrchestrationStatusFieldType::LAST_UPDATE, OrchestrationStatusResult::SUCCESS, "")
);
EXPECT_CALL(mock_status, setIsConfigurationUpdated(A<EnumArray<OrchestrationStatusConfigType, bool>>())
).WillOnce(
Invoke(
[](EnumArray<OrchestrationStatusConfigType, bool> arr)
{
EXPECT_EQ(arr[OrchestrationStatusConfigType::MANIFEST], false);
EXPECT_EQ(arr[OrchestrationStatusConfigType::POLICY], true);
EXPECT_EQ(arr[OrchestrationStatusConfigType::SETTINGS], false);
}
)
);
EXPECT_CALL(mock_ml, yield(A<chrono::microseconds>()))
.WillOnce(
Invoke(
[] (chrono::microseconds microseconds)
{
EXPECT_EQ(1000000, microseconds.count());
}
)
)
.WillOnce(
Invoke(
[] (chrono::microseconds microseconds)
{
EXPECT_EQ(25000000, microseconds.count());
throw invalid_argument("stop while loop");
}
)
);
EXPECT_CALL(
mock_shell_cmd,
getExecOutput(_, _, _)
).WillRepeatedly(Return(string("daniel\n1\n")));
EXPECT_CALL(mock_service_controller, clearFailedServices());
EXPECT_CALL(mock_service_controller, doesFailedServicesExist()).WillOnce(Return(true));
EXPECT_CALL(
mock_service_controller,
updateServiceConfiguration(policy_file_path_bk, _, _, _, _, _)
).WillOnce(Return(true));
EXPECT_CALL(
mock_orchestration_tools,
copyFile(policy_file_path_bk, policy_file_path)
).WillOnce(Return(true));
try {
runRoutine();
} catch (const invalid_argument& e) {}
}
TEST_F(OrchestrationTest, orchestrationPolicyUpdate)
{
waitForRestCall();
@@ -597,6 +823,9 @@ TEST_F(OrchestrationTest, orchestrationPolicyUpdate)
)
);
set<string> expected_changed_policies = {};
EXPECT_CALL(mock_service_controller, mockMoveChangedPolicies()).WillOnce(Return(expected_changed_policies));
EXPECT_CALL(mock_status, setFogAddress(new_host_url));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, readFile(orchestration_policy_file_path))
@@ -628,7 +857,6 @@ TEST_F(OrchestrationTest, orchestrationPolicyUpdate)
.WillOnce(ReturnRef(second_val))
.WillOnce(ReturnRef(third_val)
);
EXPECT_CALL(mock_status, setPolicyVersion(first_policy_version));
EXPECT_CALL(mock_status, setPolicyVersion(third_val));
EXPECT_CALL(mock_update_communication, sendPolicyVersion("13")).Times(1).WillOnce(Return(Maybe<void>()));
@@ -781,7 +1009,6 @@ TEST_F(OrchestrationTest, startOrchestrationPoliceWithFailures)
EXPECT_CALL(mock_service_controller, getPolicyVersion())
.Times(2).WillRepeatedly(ReturnRef(first_policy_version));
EXPECT_CALL(mock_status, setPolicyVersion(first_policy_version));
EXPECT_CALL(mock_update_communication, getUpdate(_)).WillOnce(
Invoke(
@@ -910,7 +1137,6 @@ TEST_F(OrchestrationTest, loadOrchestrationPolicyFromBackup)
EXPECT_CALL(mock_service_controller, getPolicyVersion())
.Times(2).WillRepeatedly(ReturnRef(first_policy_version));
EXPECT_CALL(mock_status, setPolicyVersion(first_policy_version));
EXPECT_CALL(mock_update_communication, getUpdate(_)).WillOnce(
Invoke(
[&](CheckUpdateRequest &req)
@@ -1039,7 +1265,6 @@ TEST_F(OrchestrationTest, manifestUpdate)
EXPECT_CALL(mock_service_controller, getPolicyVersion())
.Times(2).WillRepeatedly(ReturnRef(first_policy_version));
EXPECT_CALL(mock_status, setPolicyVersion(first_policy_version));
EXPECT_CALL(mock_update_communication, getUpdate(_)).WillOnce(
Invoke(
[&](CheckUpdateRequest &req)
@@ -1165,11 +1390,14 @@ TEST_F(OrchestrationTest, getBadPolicyUpdate)
EXPECT_CALL(mock_status, setFogAddress(host_url));
vector<string> expected_data_types = {};
EXPECT_CALL(
mock_service_controller,
updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _)
).Times(2).WillRepeatedly(Return(true));
set<string> expected_changed_policies = {};
EXPECT_CALL(mock_service_controller, mockMoveChangedPolicies()).WillOnce(Return(expected_changed_policies));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, readFile(orchestration_policy_file_path)).WillOnce(Return(response));
EXPECT_CALL(mock_orchestration_tools, copyFile(new_policy_path, policy_file_path + ".last"))
@@ -1215,7 +1443,6 @@ TEST_F(OrchestrationTest, getBadPolicyUpdate)
.WillOnce(ReturnRef(first_policy_version))
.WillOnce(ReturnRef(second_val)
);
EXPECT_CALL(mock_status, setPolicyVersion(first_policy_version));
EXPECT_CALL(mock_status, setLastUpdateAttempt());
EXPECT_CALL(
mock_status,
@@ -1250,8 +1477,8 @@ TEST_F(OrchestrationTest, getBadPolicyUpdate)
EXPECT_CALL(
mock_service_controller,
updateServiceConfiguration(string("policy path"), "", expected_data_types, "", "", _)).WillOnce(Return(false)
);
updateServiceConfiguration(string("policy path"), "", expected_data_types, "", "", _)
).WillOnce(Return(false));
EXPECT_CALL(mock_ml, yield(A<chrono::microseconds>()))
.WillOnce(
@@ -1343,7 +1570,6 @@ TEST_F(OrchestrationTest, failedDownloadSettings)
EXPECT_CALL(mock_service_controller, getPolicyVersion())
.Times(2).WillRepeatedly(ReturnRef(first_policy_version));
EXPECT_CALL(mock_status, setPolicyVersion(first_policy_version));
EXPECT_CALL(mock_update_communication, getUpdate(_)).WillOnce(
Invoke(
[&](CheckUpdateRequest &req)
@@ -1374,7 +1600,6 @@ TEST_F(OrchestrationTest, failedDownloadSettings)
manifest_err
)
).Times(1);
EXPECT_CALL(mock_details_resolver, getHostname()).Times(2).WillRepeatedly(Return(string("hostname")));
EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(manifest_err));
EXPECT_CALL(mock_status, setIsConfigurationUpdated(A<EnumArray<OrchestrationStatusConfigType, bool>>())
@@ -1400,13 +1625,6 @@ TEST_F(OrchestrationTest, failedDownloadSettings)
manifest_file
)
).WillOnce(Return(download_error));
EXPECT_CALL(mock_downloader,
downloadFileFromFog(
string("policy-checksum"),
Package::ChecksumTypes::SHA256,
policy_file
)
).WillOnce(Return(download_error));
EXPECT_CALL(mock_downloader,
downloadFileFromFog(
string("settings-checksum"),
@@ -1754,7 +1972,6 @@ TEST_F(OrchestrationTest, dataUpdate)
EXPECT_CALL(mock_service_controller, getPolicyVersion())
.Times(2).WillRepeatedly(ReturnRef(first_policy_version));
EXPECT_CALL(mock_status, setPolicyVersion(first_policy_version));
EXPECT_CALL(mock_update_communication, getUpdate(_)).WillOnce(
Invoke(
[&](CheckUpdateRequest &req)

View File

@@ -181,6 +181,11 @@ ServiceDetails::serialize(Archive &ar)
ReconfStatus
ServiceDetails::sendNewConfigurations(int configuration_id, const string &policy_version)
{
if(!isServiceActive()) {
dbgDebug(D_ORCHESTRATOR) << "Service " << service_name << " is inactive";
return ReconfStatus::INACTIVE;
}
SendConfigurations new_config(configuration_id, policy_version);
I_Messaging *messaging = Singleton::Consume<I_Messaging>::by<ServiceController>();
@@ -194,14 +199,12 @@ ServiceDetails::sendNewConfigurations(int configuration_id, const string &policy
conn_flags,
"/set-new-configuration"
);
if (!res) {
if(!isServiceActive()) {
dbgDebug(D_ORCHESTRATOR) << "Service " << service_name << " is inactive";
return ReconfStatus::INACTIVE;
}
dbgDebug(D_ORCHESTRATOR) << "Service " << service_name << " didn't respond to new configuration request";
return ReconfStatus::FAILED;
}
auto service_details = Singleton::Consume<I_ServiceController>::by<ServiceDetails>();
if (new_config.finished.get()) {
@@ -300,6 +303,8 @@ public:
void clearFailedServices() override;
set<string> && moveChangedPolicies() override;
private:
void cleanUpVirtualFiles();
@@ -320,6 +325,8 @@ private:
void loadRegisteredServicesFromFile();
void writeRegisteredServicesToFile();
bool backupConfigurationFile(const string &configuration_file_path);
int configuration_id = 0;
map<string, ServiceDetails> registered_services;
map<string, ServiceDetails> pending_services;
@@ -332,6 +339,10 @@ private:
map<int, string> services_reconf_ids;
string filesystem_prefix;
bool is_multi_tenant_env = false;
set<string> changed_policy_files;
I_OrchestrationTools *orchestration_tools = nullptr;
I_MainLoop *mainloop = nullptr;
};
class GetServicesPorts : public ServerRest
@@ -410,6 +421,12 @@ ServiceController::Impl::doesFailedServicesExist()
}
// LCOV_EXCL_STOP
set<string> &&
ServiceController::Impl::moveChangedPolicies()
{
return move(changed_policy_files);
}
void
ServiceController::Impl::init()
{
@@ -418,6 +435,9 @@ ServiceController::Impl::init()
rest->addRestCall<GetServicesPorts>(RestAction::SHOW, "all-service-ports");
rest->addRestCall<ServiceReconfStatusMonitor>(RestAction::SET, "reconf-status");
orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<ServiceController>();
mainloop = Singleton::Consume<I_MainLoop>::by<ServiceController>();
Singleton::Consume<I_MainLoop>::by<ServiceController>()->addRecurringRoutine(
I_MainLoop::RoutineType::System,
chrono::seconds(
@@ -613,6 +633,29 @@ ServiceController::Impl::refreshPendingServices()
writeRegisteredServicesToFile();
}
bool
ServiceController::Impl::backupConfigurationFile(const string &config_file_path)
{
uint max_backup_attempts = 3;
string backup_ext = getConfigurationWithDefault<string>(".bk", "orchestration", "Backup file extension");
string backup_file = config_file_path + backup_ext;
if (!orchestration_tools->doesFileExist(config_file_path)) {
dbgTrace(D_ORCHESTRATOR) << "File does not exist. File: " << config_file_path;
return true;
}
for (size_t i = 0; i < max_backup_attempts; i++) {
if (orchestration_tools->copyFile(config_file_path, backup_file)) {
return true;
}
mainloop->yield(false);
}
dbgWarning(D_ORCHESTRATOR) << "Failed to back up the file. File: " << config_file_path;
return false;
}
bool
ServiceController::Impl::updateServiceConfiguration(
const string &new_policy_path,
@@ -665,19 +708,23 @@ ServiceController::Impl::updateServiceConfiguration(
return sendSignalForServices(nano_services_to_update, "");
}
I_OrchestrationTools *orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<ServiceController>();
Maybe<string> loaded_json = orchestration_tools->readFile(new_policy_path);
if (!loaded_json.ok()) {
Maybe<string> loaded_policy_json = orchestration_tools->readFile(new_policy_path);
if (!loaded_policy_json.ok()) {
dbgWarning(D_ORCHESTRATOR)
<< "Failed to load new file: "
<< new_policy_path
<< ". Error: "
<< loaded_json.getErr();
<< loaded_policy_json.getErr();
return false;
}
auto all_security_policies = orchestration_tools->jsonObjectSplitter(loaded_json.unpack(), tenant_id, profile_id);
auto all_security_policies = orchestration_tools->jsonObjectSplitter(
loaded_policy_json.unpack(),
tenant_id,
profile_id
);
if (!all_security_policies.ok()) {
dbgWarning(D_ORCHESTRATOR)
@@ -740,6 +787,7 @@ ServiceController::Impl::updateServiceConfiguration(
was_policy_updated = false;
continue;
}
changed_policy_files.insert(policy_file_path);
dbgInfo(D_ORCHESTRATOR) << "Successfully updated policy file. Policy name: " << single_policy.first;
@@ -779,7 +827,7 @@ ServiceController::Impl::updateServiceConfiguration(
true :
sendSignalForServices(nano_services_to_update, version_value);
dbgTrace(D_ORCHESTRATOR) << "was_policy_updated: " << (was_policy_updated ? "true" : "false");
dbgTrace(D_ORCHESTRATOR) << "was policy updated: " << (was_policy_updated ? "true" : "false");
if (was_policy_updated) {
string config_file_path;
@@ -798,24 +846,8 @@ ServiceController::Impl::updateServiceConfiguration(
return true;
}
string backup_ext = getConfigurationWithDefault<string>(".bk", "orchestration", "Backup file extension");
// Backup the current configuration file.
uint max_backup_attempts = 3;
bool is_backup_succeed = false;
string backup_file = config_file_path + backup_ext;
I_MainLoop *mainloop = Singleton::Consume<I_MainLoop>::by<ServiceController>();
for (size_t i = 0; i < max_backup_attempts; i++) {
if (orchestration_tools->copyFile(config_file_path, backup_file)) {
is_backup_succeed = true;
break;
}
mainloop->yield(false);
}
if (!is_backup_succeed) {
dbgWarning(D_ORCHESTRATOR) << "Failed to back up the policy file.";
if (!backupConfigurationFile(config_file_path)) {
dbgWarning(D_ORCHESTRATOR) << "Failed to backup the policy file.";
return false;
}
@@ -921,7 +953,6 @@ ServiceController::Impl::updateServiceConfigurationFile(
dbgFlow(D_ORCHESTRATOR) << "Updating configuration. Config Name: " << configuration_name;
I_OrchestrationTools *orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<ServiceController>();
if (orchestration_tools->doesFileExist(configuration_file_path)) {
Maybe<string> old_configuration = orchestration_tools->readFile(configuration_file_path);
if (old_configuration.ok()) {

View File

@@ -42,9 +42,7 @@ public:
EXPECT_CALL(mock_rest_api, mockRestCall(RestAction::SET, "new-configuration", _)).WillOnce(
WithArg<2>(Invoke(this, &ServiceControllerTest::setNanoServiceConfig))
);
EXPECT_CALL(mock_ml, addRecurringRoutine(I_MainLoop::RoutineType::System, _, _, _, _)).WillOnce(Return(2));
EXPECT_CALL(tenant_manager, getTimeoutVal()).WillOnce(Return(chrono::seconds(1)));
EXPECT_CALL(mock_ml, addOneTimeRoutine(I_MainLoop::RoutineType::System, _, _, false)).WillOnce(Return(1));
config.init();
@@ -257,6 +255,7 @@ TEST_F(ServiceControllerTest, UpdateConfiguration)
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
.WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(policy_file_path)).WillOnce(Return(true));
string general_settings_path = "/my/settings/path";
string reply_msg = "{\"id\": 1, \"error\": false, \"finished\": true, \"error_message\": \"\"}";
@@ -349,6 +348,29 @@ TEST_F(ServiceControllerTest, TimeOutUpdateConfiguration)
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
.WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(
mock_shell_cmd,
getExecOutput(
"/etc/cp/watchdog/cp-nano-watchdog --status --verbose --service mock access control"
" --family family1 --id id2",
_,
_
)
).Times(4).WillRepeatedly(
InvokeWithoutArgs(
[&]() -> Maybe<string>
{
static int counter = 0;
if (counter++ < 2) {
return genError("Reached timeout while executing shell command:");
}
return string("registered and running");
}
)
);
string general_settings_path = "/my/settings/path";
string reply_msg = "{\"id\": 1, \"error\": false, \"finished\": true, \"error_message\": \"\"}";
@@ -371,28 +393,6 @@ TEST_F(ServiceControllerTest, TimeOutUpdateConfiguration)
)
).WillOnce(Return(Maybe<string>(reply_msg)));
EXPECT_CALL(
mock_shell_cmd,
getExecOutput(
"/etc/cp/watchdog/cp-nano-watchdog --status --verbose --service mock access control"
" --family family1 --id id2",
_,
_
)
).Times(3).WillRepeatedly(
InvokeWithoutArgs(
[&]() -> Maybe<string>
{
static int counter = 0;
if (counter++ < 2) {
return genError("Reached timeout while executing shell command:");
}
return string("registered and running");
}
)
);
EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, general_settings_path));
EXPECT_EQ(i_service_controller->getPolicyVersion(), version_value);
EXPECT_EQ(i_service_controller->getUpdatePolicyVersion(), version_value);
@@ -468,6 +468,7 @@ TEST_F(ServiceControllerTest, writeRegisteredServicesFromFile)
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
.WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(policy_file_path)).WillOnce(Return(true));
string general_settings_path = "/my/settings/path";
string reply_msg = "{\"id\": 1, \"error\": false, \"finished\": true, \"error_message\": \"\"}";
@@ -529,9 +530,7 @@ TEST_F(ServiceControllerTest, readRegisteredServicesFromFile)
EXPECT_CALL(mock_rest_api, mockRestCall(RestAction::SET, "new-configuration", _)).WillOnce(
WithArg<2>(Invoke(this, &ServiceControllerTest::setNanoServiceConfig))
);
EXPECT_CALL(mock_ml, addRecurringRoutine(I_MainLoop::RoutineType::System, _, _, _, _)).WillOnce(Return(2));
EXPECT_CALL(tenant_manager, getTimeoutVal()).WillOnce(Return(chrono::seconds(1)));
EXPECT_CALL(mock_ml, addOneTimeRoutine(I_MainLoop::RoutineType::System, _, _, false)).WillOnce(Return(1));
config.init();
@@ -609,6 +608,7 @@ TEST_F(ServiceControllerTest, noPolicyUpdate)
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
.WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_status,
setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY));
@@ -700,6 +700,7 @@ TEST_F(ServiceControllerTest, SettingsAndPolicyUpdateCombinations)
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
.WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(
mock_shell_cmd,
@@ -742,6 +743,7 @@ TEST_F(ServiceControllerTest, SettingsAndPolicyUpdateCombinations)
EXPECT_CALL(mock_orchestration_tools, jsonObjectSplitter(new_configuration, _, _))
.WillOnce(Return(json_parser_return));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(l4_firewall_policy_path)).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, readFile(l4_firewall_policy_path)).WillOnce(Return(l4_firewall));
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
.WillOnce(Return(true));
@@ -852,6 +854,122 @@ TEST_F(ServiceControllerTest, backup)
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
.WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(
mock_shell_cmd,
getExecOutput(
"/etc/cp/watchdog/cp-nano-watchdog --status --verbose --service mock access control"
" --family family1 --id id2",
_,
_
)
).WillRepeatedly(Return(string("registered and running")));
string reply_msg = "{\"id\": 1, \"error\": false, \"finished\": true, \"error_message\": \"\"}";
EXPECT_CALL(
mock_message,
sendMessage(
_,
_,
_,
"127.0.0.1",
l4_firewall_service_port,
_,
"/set-new-configuration",
_,
_,
MessageTypeTag::GENERIC
)
).WillOnce(Return(Maybe<string>(reply_msg)));
EXPECT_EQ(i_service_controller->getPolicyVersion(), "");
EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, ""));
EXPECT_EQ(i_service_controller->getPolicyVersion(), version_value);
}
TEST_F(ServiceControllerTest, backup_file_doesnt_exist)
{
string new_configuration = "{"
" \"version\": \"" + version_value + "\""
" \"l4_firewall\":"
" {"
" \"app\": \"netfilter\","
" \"l4_firewall_rules\": ["
" {"
" \"name\": \"allow_statefull_conns\","
" \"flags\": [\"established\"],"
" \"action\": \"accept\""
" },"
" {"
" \"name\": \"icmp drop\","
" \"flags\": [\"log\"],"
" \"services\": [{\"name\":\"icmp\"}],"
" \"action\": \"drop\""
" }"
" ]"
" }"
"}";
string l4_firewall = "{"
" \"app\": \"netfilter\","
" \"l4_firewall_rules\": ["
" {"
" \"name\": \"allow_statefull_conns\","
" \"flags\": [\"established\"],"
" \"action\": \"accept\""
" },"
" {"
" \"name\": \"icmp drop\","
" \"flags\": [\"log\"],"
" \"services\": [{\"name\":\"icmp\"}],"
" \"action\": \"drop\""
" }"
" ]"
"}";
string old_configuration = "{"
" \"version\": \"" + old_version + "\""
" \"app\": \"netfilter\","
" \"l4_firewall_rules\": ["
" {"
" \"name\": \"allow_statefull_conns\","
" \"flags\": [\"established\"],"
" \"action\": \"reject\""
" },"
" {"
" \"name\": \"icmp drop\","
" \"flags\": [\"log\"],"
" \"services\": [{\"name\":\"icmp\"}],"
" \"action\": \"drop\""
" }"
" ]"
"}";
Maybe<map<string, string>> json_parser_return =
map<string, string>({{"l4_firewall", l4_firewall}, {"version", version_value}});
EXPECT_CALL(mock_orchestration_tools, readFile(file_name)).WillOnce(Return(new_configuration));
EXPECT_CALL(mock_orchestration_tools, jsonObjectSplitter(new_configuration, _, _))
.WillOnce(Return(json_parser_return));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(l4_firewall_policy_path)).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, readFile(l4_firewall_policy_path)).WillOnce(Return(old_configuration));
EXPECT_CALL(mock_orchestration_status,
setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY));
EXPECT_CALL(
mock_orchestration_tools,
copyFile(l4_firewall_policy_path, l4_firewall_policy_path + backup_extension)
).WillOnce(Return(true));
EXPECT_CALL(
mock_orchestration_tools,
writeFile(l4_firewall, l4_firewall_policy_path)).WillOnce(Return(true)
);
// backup file doesn't exist so the copyFile function should be called 0 times
EXPECT_CALL(mock_orchestration_tools, doesFileExist(policy_file_path)).WillOnce(Return(false));
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension)).Times(0);
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(
mock_shell_cmd,
@@ -997,6 +1115,7 @@ TEST_F(ServiceControllerTest, backupAttempts)
EXPECT_CALL(mock_ml, yield(false)).Times(2);
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(policy_file_path)).WillOnce(Return(true));
EXPECT_EQ(i_service_controller->getPolicyVersion(), "");
EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, ""));
EXPECT_EQ(i_service_controller->getPolicyVersion(), version_value);
@@ -1081,6 +1200,7 @@ TEST_F(ServiceControllerTest, MultiUpdateConfiguration)
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
.WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(
mock_shell_cmd,
@@ -1112,6 +1232,11 @@ TEST_F(ServiceControllerTest, MultiUpdateConfiguration)
).WillOnce(Return(Maybe<string>(reply_msg)));
EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, ""));
set<string> changed_policies = {
"/etc/cp/conf/l4_firewall/l4_firewall.policy",
"/etc/cp/conf/orchestration/orchestration.policy"
};
EXPECT_EQ(i_service_controller->moveChangedPolicies(), changed_policies);
}
class TestSendRequestToService : public ClientRest
@@ -1139,6 +1264,7 @@ TEST_F(ServiceControllerTest, emptyServices)
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
.WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(policy_file_path)).WillOnce(Return(true));
EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, ""));
}
@@ -1326,24 +1452,6 @@ TEST_F(ServiceControllerTest, ErrorUpdateConfigurationRest)
EXPECT_EQ(i_service_controller->getPolicyVersion(), "");
Flags<MessageConnConfig> conn_flags;
conn_flags.setFlag(MessageConnConfig::ONE_TIME_CONN);
EXPECT_CALL(
mock_message,
sendMessage(
true,
"{\n \"id\": 1,\n \"policy_version\": \"1.0.2\"\n}",
I_Messaging::Method::POST,
string("127.0.0.1"),
l4_firewall_service_port,
conn_flags,
string("/set-new-configuration"),
string(),
_,
MessageTypeTag::GENERIC
)
).WillOnce(Return(Maybe<string>(genError(""))));
EXPECT_TRUE(i_service_controller->isServiceInstalled("family1_id2"));
EXPECT_CALL(
@@ -1358,6 +1466,7 @@ TEST_F(ServiceControllerTest, ErrorUpdateConfigurationRest)
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
.WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(policy_file_path)).WillOnce(Return(true));
EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, ""));
EXPECT_THAT(
@@ -1568,6 +1677,7 @@ TEST_F(ServiceControllerTest, testMultitenantConfFiles)
EXPECT_CALL(mock_orchestration_tools, copyFile(new_policy_file_path, new_policy_file_path + backup_extension))
.WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, copyFile(conf_file_name, new_policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(new_policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(
mock_shell_cmd,
@@ -1665,6 +1775,7 @@ TEST_F(ServiceControllerTest, test_delayed_reconf)
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
.WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(mock_orchestration_tools, doesFileExist(policy_file_path)).WillOnce(Return(true));
EXPECT_CALL(mock_ml, yield(false)).Times(AnyNumber());
EXPECT_CALL(

View File

@@ -208,12 +208,14 @@ void ConfidenceCalculator::pullProcessedData(const std::vector<std::string>& fil
{
dbgTrace(D_WAAP) << "Fetching the confidence set object";
bool is_first_pull = true;
bool is_ok = false;
for (auto file : files)
{
ConfidenceFileDecryptor getConfFile;
bool res = sendObjectWithRetry(getConfFile,
I_Messaging::Method::GET,
getUri() + "/" + file);
is_ok |= res;
if (res && getConfFile.getConfidenceSet().ok())
{
mergeFromRemote(getConfFile.getConfidenceSet().unpack(), is_first_pull);
@@ -224,8 +226,8 @@ void ConfidenceCalculator::pullProcessedData(const std::vector<std::string>& fil
m_confidence_level = getConfFile.getConfidenceLevels().unpackMove();
}
}
// is_first_pull = false -> at least one file was downloaded and merged
if (is_first_pull) {
// is_ok = false -> no file was downloaded and merged
if (!is_ok) {
dbgError(D_WAAP_CONFIDENCE_CALCULATOR) << "Failed to get the remote state";
}
}

View File

@@ -151,9 +151,9 @@ void TrustedSourcesConfidenceCalculator::pullProcessedData(const std::vector<std
bool res = sendObjectWithRetry(getTrustFile,
I_Messaging::Method::GET,
getUri() + "/" + file);
pull_ok |= res;
if (res && getTrustFile.getTrustedLogs().ok()) {
mergeFromRemote(getTrustFile.getTrustedLogs().unpack());
pull_ok = true;
}
}
if (!pull_ok && !files.empty()) {

View File

@@ -101,6 +101,24 @@ inline unsigned char from_hex(unsigned char ch, bool &valid) {
return ch;
}
inline bool str_starts_with(const std::string& value, const std::string& prefix)
{
if (prefix.size() > value.size()) {
return false;
}
return value.compare(0, prefix.size(), prefix) == 0;
}
inline bool str_ends_with(const std::string& value, const std::string& ending)
{
if (ending.size() > value.size()) {
return false;
}
return value.compare(value.size() - ending.size(), ending.size(), ending) == 0;
}
template<class _IT>
_IT unquote_plus(_IT first, _IT last, bool decodeUrl=true, bool decodePlus=true) {
_IT result = first;

View File

@@ -89,6 +89,8 @@ WaapComponent::Impl::init(const std::string &waapDataFileName)
reputationAggregator.init();
waapStateTable = Singleton::Consume<I_Table>::by<WaapComponent>();
bool success = waf2_proc_start(waapDataFileName);
if (!success) {
dbgWarning(D_WAAP) << "WAF2 engine FAILED to initialize (probably failed to load signatures). Aborting!";
@@ -101,8 +103,6 @@ WaapComponent::Impl::init(const std::string &waapDataFileName)
I_StaticResourcesHandler *static_resources = Singleton::Consume<I_StaticResourcesHandler>::by<WaapComponent>();
static_resources->registerStaticResource("cp-ab.js", "/etc/cp/conf/waap/cp-ab.js");
static_resources->registerStaticResource("cp-csrf.js", "/etc/cp/conf/waap/cp-csrf.js");
waapStateTable = Singleton::Consume<I_Table>::by<WaapComponent>();
}
// Called when component is shut down

View File

@@ -28,17 +28,11 @@
#include <chrono>
#include <boost/regex.hpp>
#if defined(use_unwind)
#if defined(alpine) || defined(PLATFORM_x86)
#ifdef UNWIND_LIBRARY
#define UNW_LOCAL_ONLY
#include <cxxabi.h>
#include <libunwind.h>
#endif // defined(alpine) || defined(PLATFORM_x86)
#endif // defined(use_unwind)
#if !defined(alpine) && !defined(arm32_musl)
#include <execinfo.h>
#endif // not alpine && not arm32_musl
#endif // UNWIND_LIBRARY
#include "debug.h"
#include "common.h"
@@ -82,11 +76,9 @@ public:
Maybe<vector<string>>
getBacktrace() override
{
#ifdef UNWIND_LIBRARY
vector<string> symbols;
#if defined(_UCLIBC_) || defined(arm32_musl) || !defined(use_unwind)
return genError("Could not print any backtrace entries using uclibc (backtrace_symbols not supported)");
#else // not (_UCLIBC_ || arm32_musl)
#if defined(alpine) || defined(PLATFORM_x86)
unw_cursor_t cursor;
unw_context_t context;
@@ -116,24 +108,14 @@ public:
}
symbols.push_back(buf);
}
#else // not (alpine || PLATFORM_x86)
auto stack_trace_list = vector<void *>(stack_trace_max_len);
uint trace_len = backtrace(stack_trace_list.data(), stack_trace_list.size());
if (trace_len == 0 ) return genError("Could not find any backtrace entries in the current process");
char **trace_prints = backtrace_symbols(stack_trace_list.data(), trace_len);
if (trace_prints == nullptr) return genError("Could not convert backtrace entries to symbol strings");
symbols.reserve(trace_len);
for (uint i = 0; i < trace_len; ++i) {
symbols.emplace_back(trace_prints[i]);
}
free(trace_prints);
#endif // alpine || PLATFORM_x86
#endif // _UCLIBC_
return symbols;
#else // UNWIND_LIBRARY
return genError("Could not print any backtrace entries using uclibc (backtrace_symbols not supported)");
#endif // UNWIND_LIBRARY
}
private:
@@ -388,18 +370,13 @@ private:
static void
printStackTrace()
{
#ifdef UNWIND_LIBRARY
if (out_trace_file_fd == -1) return;
const char *stack_trace_title = "Stack trace:\n";
writeData(stack_trace_title, strlen(stack_trace_title));
#if defined(_UCLIBC_) || defined(arm32_musl) || !defined(use_unwind)
const char *uclibc_error =
"Could not print any backtrace entries using uclibc (backtrace_symbols not supported)\n";
writeData(uclibc_error, strlen(uclibc_error));
return;
#else // not (_UCLIBC_ || arm32_musl)
#ifdef alpine
unw_cursor_t cursor;
unw_context_t uc;
unw_getcontext(&uc);
@@ -426,19 +403,14 @@ private:
if (unw_step(&cursor) <= 0) return;
}
#else // not alpine
void *stack_trace_list[stack_trace_max_len];
uint actual_trace_len = backtrace(stack_trace_list, stack_trace_max_len);
if (actual_trace_len == 0 ) {
const char *no_bt_found_error = "Could not find any backtrace entries in the current process\n";
writeData(no_bt_found_error, strlen(no_bt_found_error));
return;
}
#else // UNWIND_LIBRARY
backtrace_symbols_fd(stack_trace_list, actual_trace_len, out_trace_file_fd);
#endif // alpine
#endif // _UCLIBC_ || arm32_musl
const char *uclibc_error =
"Could not print any backtrace entries using uclibc (backtrace_symbols not supported)\n";
writeData(uclibc_error, strlen(uclibc_error));
#endif // UNWIND_LIBRARY
}
// LCOV_EXCL_STOP

View File

@@ -101,7 +101,7 @@ deserializeStrParam(const Buffer &data, uint &cur_pos)
<< to_string(*str_size);
cur_pos += *str_size;
return move(res);
}
@@ -185,6 +185,39 @@ HttpTransactionData::createTransactionData(const Buffer &transaction_raw_data)
dbgTrace(D_NGINX_ATTACHMENT) << "Successfully deserialized client port: " << client_port.unpack();
}
if (cur_pos == transaction_raw_data.size()) {
dbgDebug(D_NGINX_ATTACHMENT)
<< "No extra data to read from buffer. This agent is working with an old "
<< "attachment version that does not contain the parsed host and parsed uri elements.";
HttpTransactionData transaction(
http_protocol.unpackMove(),
http_method.unpackMove(),
host_name.unpackMove(),
listening_addr.unpackMove(),
listening_port.unpackMove(),
uri.unpackMove(),
client_addr.unpackMove(),
client_port.unpackMove()
);
return transaction;
}
Maybe<string> ngx_parsed_host = deserializeStrParam(transaction_raw_data, cur_pos);
if (!ngx_parsed_host.ok()) {
return genError("Could not deserialize nginx host: " + ngx_parsed_host.getErr());
} else {
dbgTrace(D_NGINX_ATTACHMENT) << "Successfully deserialized nginx_host: " << ngx_parsed_host.unpack();
}
Maybe<string> ngx_parsed_uri = deserializeStrParam(transaction_raw_data, cur_pos);
if (!ngx_parsed_uri.ok()) {
return genError("Could not deserialize parsed URI: " + ngx_parsed_uri.getErr());
} else {
dbgTrace(D_NGINX_ATTACHMENT) << "Successfully deserialized parsed URI: " << ngx_parsed_uri.unpack();
}
// Fail if after parsing exact number of items, we didn't exactly consume whole buffer
if (cur_pos != transaction_raw_data.size()) {
dbgWarning(D_NGINX_ATTACHMENT) << "Nothing to deserialize, but raw data still remain";
@@ -195,14 +228,16 @@ HttpTransactionData::createTransactionData(const Buffer &transaction_raw_data)
http_protocol.unpackMove(),
http_method.unpackMove(),
host_name.unpackMove(),
ngx_parsed_host.unpackMove(),
listening_addr.unpackMove(),
listening_port.unpackMove(),
uri.unpackMove(),
ngx_parsed_uri.unpackMove(),
client_addr.unpackMove(),
client_port.unpackMove()
);
return move(transaction);
return transaction;
}
HttpTransactionData::HttpTransactionData (
@@ -214,14 +249,44 @@ HttpTransactionData::HttpTransactionData (
string _uri,
IPAddr _client_ip,
uint16_t _client_port
)
:
HttpTransactionData::HttpTransactionData(
_http_proto,
_method,
_host_name,
_host_name,
_listening_ip,
_listening_port,
_uri,
_uri,
_client_ip,
_client_port
)
{
}
HttpTransactionData::HttpTransactionData (
string _http_proto,
string _method,
string _host_name,
string _parsed_host,
IPAddr _listening_ip,
uint16_t _listening_port,
string _uri,
string _parsed_uri,
IPAddr _client_ip,
uint16_t _client_port
)
:
http_proto(move(_http_proto)),
method(move(_method)),
host_name(move(_host_name)),
parsed_host(move(_parsed_host)),
listening_ip(move(_listening_ip)),
listening_port(move(_listening_port)),
uri(move(_uri)),
parsed_uri(move(_parsed_uri)),
client_ip(move(_client_ip)),
client_port(move(_client_port)),
is_request(true),
@@ -235,9 +300,11 @@ HttpTransactionData::HttpTransactionData()
"",
"GET",
"",
"",
IPAddr(),
-1,
"",
"",
IPAddr(),
-1
)

View File

@@ -102,6 +102,8 @@ TEST_F(HttpTransactionTest, TestTransactionDataFromBuf)
EXPECT_EQ(data.getHttpProtocol(), "HTTP/1.1");
EXPECT_EQ(data.getURI(), "/user-app/");
EXPECT_EQ(data.getHttpMethod(), "GET");
EXPECT_EQ(data.getParsedURI(), "/user-app/");
EXPECT_EQ(data.getParsedHost(), "localhost");
}
TEST_F(HttpTransactionTest, TestTransactionDataBadVer)
@@ -125,3 +127,45 @@ TEST_F(HttpTransactionTest, TestTransactionDataBadAddress)
"Could not parse IP Address: String 'this.is.not.IP' is not a valid IPv4/IPv6 address"
);
}
TEST_F(HttpTransactionTest, TestTransactionDataFromBufWIthParsedHostAndParsedUri)
{
Buffer meta_data =
Buffer(encodeInt16(strlen("HTTP/1.1"))) +
Buffer("HTTP/1.1") +
encodeInt16(3) +
Buffer("GET") +
encodeInt16(9) +
Buffer("localhost") +
encodeInt16(7) +
Buffer("0.0.0.0") +
encodeInt16(443) +
encodeInt16(11) +
Buffer("//user-app/") +
encodeInt16(9) +
Buffer("127.0.0.1") +
encodeInt16(47423) +
encodeInt16(10) +
Buffer("localhost2") +
encodeInt16(10) +
Buffer("/user-app/");
HttpTransactionData data = HttpTransactionData::createTransactionData(meta_data).unpack();
stringstream data_stream;
data.print(data_stream);
string data_string(
"HTTP/1.1 GET\nFrom: 127.0.0.1:47423\nTo: localhost//user-app/ (listening on 0.0.0.0:443)\n"
);
EXPECT_EQ(data_stream.str(), data_string);
EXPECT_EQ(data.getSourceIP(), IPAddr::createIPAddr("127.0.0.1").unpack());
EXPECT_EQ(data.getSourcePort(), 47423);
EXPECT_EQ(data.getListeningIP(), IPAddr::createIPAddr("0.0.0.0").unpack());
EXPECT_EQ(data.getListeningPort(), 443);
EXPECT_EQ(data.getDestinationHost(), "localhost");
EXPECT_EQ(data.getHttpProtocol(), "HTTP/1.1");
EXPECT_EQ(data.getURI(), "//user-app/");
EXPECT_EQ(data.getHttpMethod(), "GET");
EXPECT_EQ(data.getParsedURI(), "/user-app/");
EXPECT_EQ(data.getParsedHost(), "localhost2");
}