Skip to content
Permalink
Browse files

[CMK-2113] - correct installation of file with hash and check_mk.user…

….yml

- added installation by agent new files in the root/install
- added unit tests for new file installation
- reworked Install()
- minor: added environment variable MK_INSTALLDIR and MK_MSI_PATH
- minor: removed deletion of check_mk.user.yml
- minor: names and lesser refactoring

Change-Id: Ib817f229c225f42c46755bbe27c3a9ab1573aff6
  • Loading branch information...
s-kipnis committed May 15, 2019
1 parent 85ca9f9 commit b528e459048774b3ba20d7639f0463863cc0c2a4
@@ -271,7 +271,7 @@ uint64_t ConvertToUint64(const T& Str, uint64_t Default) noexcept {
namespace win {
template <typename T>
inline bool SetEnv(const std::basic_string<T>& EnvVarName,
const std::basic_string<T>& EnvVarValue) {
const std::basic_string<T>& EnvVarValue) noexcept {
auto cmd = EnvVarName;
if constexpr (sizeof(T) == 1) {
cmd += "=" + EnvVarValue;
@@ -283,21 +283,21 @@ inline bool SetEnv(const std::basic_string<T>& EnvVarName,
}

template <typename T>
std::basic_string<T> GetEnv(const T* Name) {
T remote_machine_string[MAX_PATH];
remote_machine_string[0] = 0;
std::basic_string<T> GetEnv(const T* Name) noexcept {
T env_var_value[MAX_PATH];
env_var_value[0] = 0;

// we need constexpr here to eliminate compilation error
if constexpr (sizeof(T) == 1) {
::GetEnvironmentVariableA(Name, remote_machine_string, MAX_PATH);
::GetEnvironmentVariableA(Name, env_var_value, MAX_PATH);
} else {
::GetEnvironmentVariableW(Name, remote_machine_string, MAX_PATH);
::GetEnvironmentVariableW(Name, env_var_value, MAX_PATH);
}
return std::basic_string<T>(remote_machine_string);
return std::basic_string<T>(env_var_value);
}

template <typename T>
std::basic_string<T> GetEnv(const std::basic_string<T>& Name) {
std::basic_string<T> GetEnv(const std::basic_string<T>& Name) noexcept {
return GetEnv(Name.c_str());
}

@@ -145,15 +145,17 @@ constexpr const wchar_t* kAgentBin = L"bin"; // legacy for OHM
constexpr const wchar_t* kAgentProviders = L"providers"; // only agent's exe
constexpr const wchar_t* kAgentUtils = L"utils"; // anything to use
constexpr const wchar_t* kAgentMrpe = L"mrpe"; // mrpe
constexpr const wchar_t* kFileInstallDir = L"install"; // from here!

// ProgramData/CheckMK/Agent
constexpr const wchar_t* kCache = L"cache"; // owned by agent
constexpr const wchar_t* kUserPlugins = L"plugins"; // owned by user
constexpr const wchar_t* kLocal = L"local"; // owned by user
constexpr const wchar_t* kInstall = L"install"; // owned by site
constexpr const wchar_t* kBakery = L"bakery"; // owned by site
constexpr const wchar_t* kState = L"state"; // owned by plugins
constexpr const wchar_t* kPluginConfig = L"config"; // owned by plugins
constexpr const wchar_t* kCache = L"cache"; // owned by agent
constexpr const wchar_t* kUserPlugins = L"plugins"; // owned by user
constexpr const wchar_t* kLocal = L"local"; // owned by user
constexpr const wchar_t* kInstall = L"install"; // owned by agent
constexpr const wchar_t* kUserInstallDir = L"install"; // owned by agent
constexpr const wchar_t* kBakery = L"bakery"; // owned by site
constexpr const wchar_t* kState = L"state"; // owned by plugins
constexpr const wchar_t* kPluginConfig = L"config"; // owned by plugins

constexpr const wchar_t* kSpool = L"spool"; // owned by user/sys plugins
constexpr const wchar_t* kTemp = L"temp"; // owned by user plugins
@@ -173,6 +175,9 @@ constexpr const char* const kMkLogDirName = "MK_LOGDIR";
constexpr const char* const kRemoteHost = "REMOTE_HOST";
constexpr const char* const kRemote = "REMOTE";

constexpr std::string_view kMkInstallDirName = "MK_INSTALLDIR";
constexpr std::string_view kMkMsiPathName = "MK_MSI_PATH";

}; // namespace envs

// internal and stable representation of the [logwatch] event levels
@@ -259,80 +259,77 @@ bool NeedReinstall(const std::filesystem::path Target,
}

// returns true when changes had been done
bool ReinstallCaps(const std::filesystem::path TargetCap,
const std::filesystem::path SourceCap) {
bool ReinstallCaps(const std::filesystem::path target_cap,
const std::filesystem::path source_cap) {
bool changed = false;
namespace fs = std::filesystem;
std::error_code ec;
std::vector<std::wstring> files_left;
if (fs::exists(TargetCap, ec)) {
if (fs::exists(target_cap, ec)) {
if (true ==
Process(TargetCap.u8string(), ProcMode::remove, files_left)) {
XLOG::l.t("File '{}' uninstall-ed", TargetCap.u8string());
fs::remove(TargetCap, ec);
Process(target_cap.u8string(), ProcMode::remove, files_left)) {
XLOG::l.t("File '{}' uninstall-ed", target_cap.u8string());
fs::remove(target_cap, ec);
for (auto &name : files_left)
XLOG::l.i("\tRemoved '{}'", wtools::ConvertToUTF8(name));
changed = true;
}
} else
XLOG::l.t("File '{}' is absent, skipping uninstall",
TargetCap.u8string());
target_cap.u8string());

files_left.clear();
if (fs::exists(SourceCap, ec)) {
if (fs::exists(source_cap, ec)) {
if (true ==
Process(SourceCap.u8string(), ProcMode::install, files_left)) {
XLOG::l.t("File {} installed", SourceCap.u8string());
fs::copy_file(SourceCap, TargetCap, ec);
Process(source_cap.u8string(), ProcMode::install, files_left)) {
XLOG::l.t("File '{}' installed", source_cap.u8string());
fs::copy_file(source_cap, target_cap, ec);
for (auto &name : files_left)
XLOG::l.i("\tAdded '{}'", wtools::ConvertToUTF8(name));
changed = true;
}
} else
XLOG::l.t("File {} is absent, skipping install", SourceCap.u8string());
XLOG::l.t("File '{}' is absent, skipping install",
source_cap.u8string());

return changed;
}

bool ReinstallIni(const std::filesystem::path TargetIni,
const std::filesystem::path SourceIni) {
bool ReinstallIni(const std::filesystem::path target_ini,
const std::filesystem::path source_ini) {
namespace fs = std::filesystem;
std::error_code ec;

// remove old files
auto bakery_yml = cma::cfg::GetBakeryFile();
fs::remove(bakery_yml, ec);
fs::remove(TargetIni, ec);
fs::remove(target_ini, ec);

// generate new
if (fs::exists(SourceIni)) {
cma::cfg::cvt::Parser p;
p.prepare();
p.readIni(SourceIni.u8string(), false);
auto yaml = p.emitYaml();

std::ofstream ofs(bakery_yml, std::ios::binary);
if (ofs) {
ofs << cma::cfg::upgrade::MakeComments(SourceIni, true);
ofs << yaml;
}
ofs.close();
fs::copy_file(SourceIni, TargetIni, ec);
if (!fs::exists(source_ini)) return true;

cma::cfg::cvt::Parser p;
p.prepare();
p.readIni(source_ini.u8string(), false);
auto yaml = p.emitYaml();

std::ofstream ofs(bakery_yml, std::ios::binary);
if (ofs) {
ofs << cma::cfg::upgrade::MakeComments(source_ini, true);
ofs << yaml;
}
ofs.close();
fs::copy_file(source_ini, target_ini, ec);

return true;
}

void Install() {
using namespace cma::cfg;
using namespace cma::cfg::cap;
static void InstallCapFile() {
namespace fs = std::filesystem;

fs::path target_cap = cma::cfg::GetUserDir();
target_cap /= dirs::kCapInstallDir;
fs::path target_cap = cma::cfg::GetUserInstallDir();
target_cap /= files::kCapFile;
fs::path source_cap = cma::cfg::GetRootDir();
source_cap /= dirs::kCapInstallDir;

fs::path source_cap = cma::cfg::GetFileInstallDir();
source_cap /= files::kCapFile;

XLOG::l.t("Installing cap file '{}'", source_cap.u8string());
@@ -343,15 +340,16 @@ void Install() {
} else
XLOG::l.t(
"Installing of CAP file is not required, the file is already installed");
}

static void InstallIniFile() {
namespace fs = std::filesystem;

fs::path target_ini = cma::cfg::GetUserDir();
target_ini /= dirs::kCapInstallDir;
fs::path target_ini = cma::cfg::GetUserInstallDir();
target_ini /= files::kIniFile;
fs::path source_ini = cma::cfg::GetRootDir();
source_ini /= dirs::kCapInstallDir;
fs::path source_ini = cma::cfg::GetFileInstallDir();
source_ini /= files::kIniFile;

std::error_code ec;
XLOG::l.t("Installing ini file '{}'", source_ini.u8string());
if (NeedReinstall(target_ini, source_ini)) {
XLOG::l.i("Reinstalling '{}' with '{}'", target_ini.u8string(),
@@ -362,4 +360,83 @@ void Install() {
"Installing of INI file is not required, the file is already installed");
}

static void PrintInstallCopyLog(std::string_view info_on_error,
std::filesystem::path in_file,
std::filesystem::path out_file,
const std::error_code &ec) noexcept {
if (ec.value() == 0)
XLOG::l.i("\tSuccess");
else
XLOG::d("\t{} in '{}' out '{}' error [{}] '{}'", info_on_error,
in_file.u8string(), out_file.u8string(), ec.value(),
ec.message());
}

static std::string KillTrailingCR(std::string &&message) {
if (!message.empty() && message.back() == '\n') message.pop_back();
if (!message.empty() && message.back() == '\r') message.pop_back(); // win
return std::move(message);
}

// true when copy or copy not required
// false on error
bool InstallFileAsCopy(std::wstring_view filename, // checkmk.dat
std::wstring_view target_dir, // @user
std::wstring_view source_dir) // @root/install
noexcept {
namespace fs = std::filesystem;

std::error_code ec;
fs::path target_file = target_dir;
if (!fs::is_directory(target_dir, ec)) {
XLOG::l.i("Target Folder '{}' is suspicious [{}] '{}'",
target_file.u8string(), ec.value(),
KillTrailingCR(ec.message()));
return false;
}

target_file /= filename;
fs::path source_file = source_dir;
source_file /= filename;

XLOG::l.t("Copy file '{}' to '{}'", source_file.u8string(),
target_file.u8string());

if (!fs::exists(source_file, ec)) {
// special case, no source file => remove target file
fs::remove(target_file, ec);
PrintInstallCopyLog("Remove failed", source_file, target_file, ec);
return true;
}

if (!cma::tools::IsValidRegularFile(source_file)) {
XLOG::l.i("File '{}' is bad", source_file.u8string());
return false;
}

if (NeedReinstall(target_file, source_file)) {
XLOG::l.i("Reinstalling '{}' with '{}'", target_file.u8string(),
source_file.u8string());

fs::copy_file(source_file, target_file,
fs::copy_options::overwrite_existing, ec);
PrintInstallCopyLog("Copy failed", source_file, target_file, ec);
} else
XLOG::l.t("Copy is not required, the file is already exists");
return true;
}

void Install() {
using namespace cma::cfg;
using namespace cma::cfg::cap;

InstallCapFile();
InstallIniFile();

auto source = GetFileInstallDir();

InstallFileAsCopy(files::kDatFile, GetUserInstallDir(), source);
InstallFileAsCopy(files::kUserYmlFile, GetUserDir(), source);
}

} // namespace cma::cfg::cap
@@ -11,15 +11,20 @@
#include <tuple>

#include "common/cfg_info.h"

#include "common/wtools.h"

#include "logger.h"

namespace cma::cfg::cap {

// main API
void Install();

// support
bool InstallFileAsCopy(std::wstring_view filename, // checkmk.dat
std::wstring_view target_dir, // @user
std::wstring_view source_dir) // @root/install
noexcept;

bool NeedReinstall(const std::filesystem::path Target,
const std::filesystem::path Src);

@@ -222,21 +222,26 @@ std::wstring GetBakeryDir() noexcept {
}

std::filesystem::path GetBakeryFile() noexcept {
std::filesystem::path bakery = details::G_ConfigInfo.getBakeryDir();
auto bakery = details::G_ConfigInfo.getBakeryDir();
bakery /= files::kDefaultMainConfig;
bakery.replace_extension(files::kDefaultBakeryExt);
return bakery;
}

std::wstring GetMsiBackupDir() noexcept {
std::filesystem::path data_dir = details::G_ConfigInfo.getUserDir();
return data_dir / dirs::kMsiInstallDir;
std::wstring GetUserInstallDir() noexcept {
auto data_dir = details::G_ConfigInfo.getUserDir();
return data_dir / dirs::kUserInstallDir;
}

std::wstring GetRootDir() noexcept {
return details::G_ConfigInfo.getRootDir();
}

std::wstring GetFileInstallDir() noexcept {
auto root = details::G_ConfigInfo.getRootDir();
return root / dirs::kFileInstallDir;
}

std::wstring GetLocalDir() noexcept {
return details::G_ConfigInfo.getLocalDir();
}
@@ -750,14 +755,17 @@ YAML::Node LoadAndCheckYamlFile(const std::wstring& FileName,
void SetupPluginEnvironment() {
using namespace std;
std::pair<std::string, std::wstring> dirs[] = {
//
// string conversion is required because of string used in interfaces
// of SetEnv and ConvertToUTF8
{string(envs::kMkLocalDirName), cma::cfg::GetLocalDir()},
{string(envs::kMkStateDirName), cma::cfg::GetStateDir()},
{string(envs::kMkPluginsDirName), cma::cfg::GetUserPluginsDir()},
{string(envs::kMkTempDirName), cma::cfg::GetTempDir()},
{string(envs::kMkLogDirName), cma::cfg::GetLogDir()},
{string(envs::kMkConfDirName), cma::cfg::GetPluginConfigDir()},
{string(envs::kMkSpoolDirName), cma::cfg::GetSpoolDir()},
{string(envs::kMkInstallDirName), cma::cfg::GetUserInstallDir()},
{string(envs::kMkMsiPathName), cma::cfg::GetUpdateDir()},
//
};

Oops, something went wrong.

0 comments on commit b528e45

Please sign in to comment.
You can’t perform that action at this time.