Skip to content

Commit

Permalink
Make /var/lib/icinga2/api/zones a symlink to /var/lib/icinga2/api/zon…
Browse files Browse the repository at this point in the history
…es-stage/*

refs #7742
  • Loading branch information
Al2Klimov committed Mar 23, 2020
1 parent ddce583 commit b06c161
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 40 deletions.
61 changes: 23 additions & 38 deletions lib/remote/apilistener-filesync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "base/application.hpp"
#include "base/exception.hpp"
#include "base/utility.hpp"
#include <boost/filesystem.hpp>
#include <fstream>
#include <iomanip>

Expand Down Expand Up @@ -310,11 +311,6 @@ Value ApiListener::ConfigUpdateHandler(const MessageOrigin::Ptr& origin, const D
return Empty;
}

/* Only one transaction is allowed, concurrent message handlers need to wait.
* This affects two parent endpoints sending the config in the same moment.
*/
boost::mutex::scoped_lock lock(m_ConfigSyncStageLock);

String apiZonesStageDir = GetApiZonesStageDir();
String fromEndpointName = origin->FromClient->GetEndpoint()->GetName();
String fromZoneName = GetFromZoneName(origin->FromZone);
Expand All @@ -339,16 +335,8 @@ Value ApiListener::ConfigUpdateHandler(const MessageOrigin::Ptr& origin, const D
// Keep track of the relative config paths for later validation and copying. TODO: Find a better algorithm.
std::vector<String> relativePaths;

/*
* We can and must safely purge the staging directory, as the difference is taken between
* runtime production config and newly received configuration.
* This is needed to not mix deleted/changed content between received and stage
* config.
*/
if (Utility::PathExists(apiZonesStageDir))
Utility::RemoveDirRecursive(apiZonesStageDir);

Utility::MkDirP(apiZonesStageDir, 0700);
apiZonesStageDir = Utility::CreateTempDir(apiZonesStageDir + "/" + Convert::ToString(Utility::GetTime()) + "-XXXXXX", 0700) + "/";

// Analyse and process the update.
size_t count = 0;
Expand Down Expand Up @@ -380,7 +368,7 @@ Value ApiListener::ConfigUpdateHandler(const MessageOrigin::Ptr& origin, const D

// Put the received configuration into our stage directory.
String productionConfigZoneDir = GetApiZonesDir() + zoneName;
String stageConfigZoneDir = GetApiZonesStageDir() + zoneName;
String stageConfigZoneDir = apiZonesStageDir + zoneName;

Utility::MkDirP(productionConfigZoneDir, 0700);
Utility::MkDirP(stageConfigZoneDir, 0700);
Expand Down Expand Up @@ -521,11 +509,13 @@ Value ApiListener::ConfigUpdateHandler(const MessageOrigin::Ptr& origin, const D
Log(LogInformation, "ApiListener")
<< "Received configuration updates (" << count << ") from endpoint '" << fromEndpointName
<< "' are different to production, triggering validation and reload.";
AsyncTryActivateZonesStage(relativePaths);
AsyncTryActivateZonesStage(relativePaths, apiZonesStageDir);
} else {
Log(LogInformation, "ApiListener")
<< "Received configuration updates (" << count << ") from endpoint '" << fromEndpointName
<< "' are equal to production, skipping validation and reload.";

Utility::RemoveDirRecursive(apiZonesStageDir);
}

return Empty;
Expand All @@ -541,10 +531,10 @@ Value ApiListener::ConfigUpdateHandler(const MessageOrigin::Ptr& origin, const D
* @param relativePaths Collected paths including the zone name, which are copied from stage to current directories.
*/
void ApiListener::TryActivateZonesStageCallback(const ProcessResult& pr,
const std::vector<String>& relativePaths)
const std::vector<String>& relativePaths, const String& apiZonesStageDir)
{
namespace fs = boost::filesystem;
String apiZonesDir = GetApiZonesDir();
String apiZonesStageDir = GetApiZonesStageDir();

String logFile = apiZonesStageDir + "/startup.log";
std::ofstream fpLog(logFile.CStr(), std::ofstream::out | std::ostream::binary | std::ostream::trunc);
Expand All @@ -561,26 +551,19 @@ void ApiListener::TryActivateZonesStageCallback(const ProcessResult& pr,
Log(LogInformation, "ApiListener")
<< "Config validation for stage '" << apiZonesStageDir << "' was OK, replacing into '" << apiZonesDir << "' and triggering reload.";

// Purge production before copying stage.
if (Utility::PathExists(apiZonesDir))
Utility::RemoveDirRecursive(apiZonesDir);

Utility::MkDirP(apiZonesDir, 0700);

// Copy all synced configuration files from stage to production.
for (const String& path : relativePaths) {
if (!Utility::PathExists(apiZonesStageDir + path))
continue;

Log(LogInformation, "ApiListener")
<< "Copying file '" << path << "' from config sync staging to production zones directory.";
{
boost::mutex::scoped_lock lock(m_ConfigSyncStageLock);

String stagePath = apiZonesStageDir + path;
String currentPath = apiZonesDir + path;
// Purge production before copying stage.
if (Utility::PathExists(apiZonesDir)) {
if (fs::is_symlink(apiZonesDir.GetData())) {
fs::remove_all(fs::read_symlink(apiZonesDir.GetData()));
}

Utility::MkDirP(Utility::DirName(currentPath), 0700);
Utility::RemoveDirRecursive(apiZonesDir);
}

Utility::CopyFile(stagePath, currentPath);
fs::create_symlink(apiZonesStageDir.GetData(), apiZonesDir.GetData());
}

// Clear any failed deployment before
Expand All @@ -604,6 +587,8 @@ void ApiListener::TryActivateZonesStageCallback(const ProcessResult& pr,

if (listener)
listener->UpdateLastFailedZonesStageValidation(pr.Output);

Utility::RemoveDirRecursive(apiZonesStageDir);
}

/**
Expand All @@ -612,7 +597,7 @@ void ApiListener::TryActivateZonesStageCallback(const ProcessResult& pr,
*
* @param relativePaths Required for later file operations in the callback. Provides the zone name plus path in a list.
*/
void ApiListener::AsyncTryActivateZonesStage(const std::vector<String>& relativePaths)
void ApiListener::AsyncTryActivateZonesStage(const std::vector<String>& relativePaths, const String& apiZonesStageDir)
{
VERIFY(Application::GetArgC() >= 1);

Expand All @@ -634,11 +619,11 @@ void ApiListener::AsyncTryActivateZonesStage(const std::vector<String>& relative

// Set the ZonesStageDir. This creates our own local chroot without any additional automated zone includes.
args->Add("--define");
args->Add("System.ZonesStageVarDir=" + GetApiZonesStageDir());
args->Add("System.ZonesStageVarDir=" + apiZonesStageDir);

Process::Ptr process = new Process(Process::PrepareCommand(args));
process->SetTimeout(Application::GetReloadTimeout());
process->Run(std::bind(&TryActivateZonesStageCallback, _1, relativePaths));
process->Run(std::bind(&TryActivateZonesStageCallback, _1, relativePaths, apiZonesStageDir));
}

/**
Expand Down
4 changes: 2 additions & 2 deletions lib/remote/apilistener.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,8 @@ class ApiListener final : public ObjectImpl<ApiListener>
static void ConfigGlobHandler(ConfigDirInformation& config, const String& path, const String& file);

static void TryActivateZonesStageCallback(const ProcessResult& pr,
const std::vector<String>& relativePaths);
static void AsyncTryActivateZonesStage(const std::vector<String>& relativePaths);
const std::vector<String>& relativePaths, const String& apiZonesStageDir);
static void AsyncTryActivateZonesStage(const std::vector<String>& relativePaths, const String& apiZonesStageDir);

static String GetChecksum(const String& content);
static bool CheckConfigChange(const ConfigDirInformation& oldConfig, const ConfigDirInformation& newConfig);
Expand Down

0 comments on commit b06c161

Please sign in to comment.