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

@@ -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(