mirror of https://github.com/Icinga/icinga2.git
Implement support for the --env command-line argument
This commit is contained in:
parent
c7e61748d4
commit
c577554073
|
@ -32,6 +32,8 @@
|
|||
#include "base/context.hpp"
|
||||
#include "base/console.hpp"
|
||||
#include "base/process.hpp"
|
||||
#include "base/json.hpp"
|
||||
#include "base/tcpsocket.hpp"
|
||||
#include "config.h"
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
|
@ -46,6 +48,9 @@
|
|||
# include <Lmcons.h>
|
||||
# include <Shellapi.h>
|
||||
# include <tchar.h>
|
||||
|
||||
# define popen _popen
|
||||
# define pclose _pclose
|
||||
#endif /* _WIN32 */
|
||||
|
||||
using namespace icinga;
|
||||
|
@ -215,8 +220,6 @@ static int Main()
|
|||
Application::DeclareConcurrency(std::thread::hardware_concurrency());
|
||||
Application::DeclareMaxConcurrentChecks(Application::GetDefaultMaxConcurrentChecks());
|
||||
|
||||
ScriptGlobal::Set("Environment", "production");
|
||||
|
||||
ScriptGlobal::Set("AttachDebugger", false);
|
||||
|
||||
ScriptGlobal::Set("PlatformKernel", Utility::GetPlatformKernel());
|
||||
|
@ -247,7 +250,8 @@ static int Main()
|
|||
("include,I", po::value<std::vector<std::string> >(), "add include search directory")
|
||||
("log-level,x", po::value<std::string>(), "specify the log level for the console log.\n"
|
||||
"The valid value is either debug, notice, information (default), warning, or critical")
|
||||
("script-debugger,X", "whether to enable the script debugger");
|
||||
("script-debugger,X", "whether to enable the script debugger")
|
||||
("env", po::value<std::string>(), "the name of the environment, e.g. \"production\"");
|
||||
|
||||
po::options_description hiddenDesc("Hidden options");
|
||||
|
||||
|
@ -271,6 +275,99 @@ static int Main()
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (vm.count("env") && vm["env"].as<std::string>() != "") {
|
||||
String env = vm["env"].as<std::string>();
|
||||
ScriptGlobal::Set("Environment", env);
|
||||
} else {
|
||||
#ifndef _WIN32
|
||||
String cmd = "icinga-envs";
|
||||
#else /* _WIN32 */
|
||||
String cmd = "\"" + Utility::DirName(Application::GetExePath(argv[0])) + "\\icinga-envs.exe" + "\"";
|
||||
#endif /* _WIN32 */
|
||||
cmd += " get-default";
|
||||
#ifndef _WIN32
|
||||
cmd += " 2>/dev/null";
|
||||
#else /* _WIN32 */
|
||||
cmd += " 2>NUL";
|
||||
cmd = "\"" + cmd + "\"";
|
||||
#endif /* _WIN32 */
|
||||
|
||||
FILE *fp = popen(cmd.CStr(), "r");
|
||||
std::stringstream msgbuf;
|
||||
while (!ferror(fp) && !feof(fp)) {
|
||||
char buf[512];
|
||||
size_t num = fread(buf, 1, sizeof(buf), fp);
|
||||
msgbuf << std::string(buf, buf + num);
|
||||
}
|
||||
pclose(fp);
|
||||
|
||||
String env = msgbuf.str();
|
||||
ScriptGlobal::Set("Environment", env.Trim());
|
||||
}
|
||||
|
||||
String env = ScriptGlobal::Get("Environment", NULL);
|
||||
#ifndef _WIN32
|
||||
String cmd = "icinga-envs";
|
||||
#else /* _WIN32 */
|
||||
String cmd = "\"" + Utility::DirName(Application::GetExePath(argv[0])) + "\\icinga-envs.exe" + "\"";
|
||||
#endif /* _WIN32 */
|
||||
cmd += " info --json " + Utility::EscapeShellArg(env);
|
||||
#ifndef _WIN32
|
||||
cmd += " 2>/dev/null";
|
||||
#else /* _WIN32 */
|
||||
cmd += " 2>NUL";
|
||||
cmd = "\"" + cmd + "\"";
|
||||
#endif /* _WIN32 */
|
||||
|
||||
FILE *fp = popen(cmd.CStr(), "r");
|
||||
std::stringstream msgbuf;
|
||||
while (!ferror(fp) && !feof(fp)) {
|
||||
char buf[512];
|
||||
size_t num = fread(buf, 1, sizeof(buf), fp);
|
||||
msgbuf << std::string(buf, buf + num);
|
||||
}
|
||||
pclose(fp);
|
||||
|
||||
Dictionary::Ptr envInfo;
|
||||
try {
|
||||
envInfo = JsonDecode(msgbuf.str());
|
||||
} catch (const std::exception&) {}
|
||||
|
||||
if (envInfo) {
|
||||
Dictionary::Ptr config = envInfo->Get("config");
|
||||
|
||||
if (!config) {
|
||||
Log(LogCritical, "app")
|
||||
<< "Invalid JSON returned by icinga-envs: " << msgbuf.str();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
String configPath = config->Get("config_path");
|
||||
String dataPath = config->Get("data_path");
|
||||
|
||||
ScriptGlobal::Set("SysconfDir", configPath);
|
||||
ScriptGlobal::Set("RunDir", dataPath + "/run");
|
||||
ScriptGlobal::Set("LocalStateDir", dataPath);
|
||||
|
||||
TcpSocket::Ptr agentListener = new TcpSocket();
|
||||
agentListener->Bind("127.0.0.1", "0", AF_INET);
|
||||
auto pieces = agentListener->GetClientAddress().Split(":");
|
||||
config->Set("port", Convert::ToLong(pieces[pieces.size() - 1]));
|
||||
|
||||
Dictionary::Ptr envData = new Dictionary({
|
||||
{ "listener", agentListener },
|
||||
{ "config", config },
|
||||
{ "meta_path", envInfo->Get("env_path") + "/config.json" }
|
||||
});
|
||||
|
||||
// Make the agent listener available to the ApiListener later on
|
||||
ScriptGlobal::Set("EnvironmentInfo", envData);
|
||||
} else if (env != "") {
|
||||
Log(LogCritical, "app")
|
||||
<< "No such environment exists: " << env;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
char username[UNLEN + 1];
|
||||
DWORD usernameLen = UNLEN + 1;
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
<Binary Id="icinga2_installer" SourceFile="$<TARGET_FILE:icinga-installer>" />
|
||||
|
||||
<InstallExecuteSequence>
|
||||
<Custom Action="XtraUpgradeNSIS" After="InstallInitialize">$CM_CP_sbin.icinga2_installer.exe>2</Custom>
|
||||
<Custom Action="XtraInstall" Before="InstallFinalize">$CM_CP_sbin.icinga2_installer.exe>2</Custom>
|
||||
<Custom Action="XtraUninstall" Before="RemoveExistingProducts">$CM_CP_sbin.icinga2_installer.exe=2</Custom>
|
||||
<Custom Action="XtraUpgradeNSIS" After="InstallInitialize">$CM_CP_sbin.icinga2_installer.exe>2 AND NOT SUPPRESS_XTRA</Custom>
|
||||
<Custom Action="XtraInstall" Before="InstallFinalize">$CM_CP_sbin.icinga2_installer.exe>2 AND NOT SUPPRESS_XTRA</Custom>
|
||||
<Custom Action="XtraUninstall" Before="RemoveExistingProducts">$CM_CP_sbin.icinga2_installer.exe=2 AND NOT SUPPRESS_XTRA</Custom>
|
||||
</InstallExecuteSequence>
|
||||
|
||||
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Run Icinga 2 setup wizard" />
|
||||
|
|
|
@ -49,6 +49,14 @@ int ApiSetupCommand::GetMaxArguments() const
|
|||
return -1;
|
||||
}
|
||||
|
||||
void ApiSetupCommand::InitParameters(boost::program_options::options_description& visibleDesc,
|
||||
boost::program_options::options_description& hiddenDesc) const
|
||||
{
|
||||
visibleDesc.add_options()
|
||||
("quiet,q", "be less verbose")
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* The entry point for the "api setup" CLI command.
|
||||
*
|
||||
|
@ -56,12 +64,15 @@ int ApiSetupCommand::GetMaxArguments() const
|
|||
*/
|
||||
int ApiSetupCommand::Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const
|
||||
{
|
||||
if (vm.count("quiet"))
|
||||
Logger::SetConsoleLogSeverity(LogWarning);
|
||||
|
||||
String cn = VariableUtility::GetVariable("NodeName");
|
||||
|
||||
if (cn.IsEmpty())
|
||||
cn = Utility::GetFQDN();
|
||||
|
||||
if (!ApiSetupUtility::SetupMaster(cn, true))
|
||||
if (!ApiSetupUtility::SetupMaster(cn, true, vm.count("quiet")))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -38,6 +38,8 @@ public:
|
|||
String GetDescription() const override;
|
||||
String GetShortDescription() const override;
|
||||
int GetMaxArguments() const override;
|
||||
void InitParameters(boost::program_options::options_description& visibleDesc,
|
||||
boost::program_options::options_description& hiddenDesc) const override;
|
||||
int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const override;
|
||||
ImpersonationLevel GetImpersonationLevel() const override;
|
||||
};
|
||||
|
|
|
@ -48,7 +48,7 @@ String ApiSetupUtility::GetApiUsersConfPath()
|
|||
return ApiSetupUtility::GetConfdPath() + "/api-users.conf";
|
||||
}
|
||||
|
||||
bool ApiSetupUtility::SetupMaster(const String& cn, bool prompt_restart)
|
||||
bool ApiSetupUtility::SetupMaster(const String& cn, bool prompt_restart, bool quiet)
|
||||
{
|
||||
if (!SetupMasterCertificates(cn))
|
||||
return false;
|
||||
|
@ -56,13 +56,13 @@ bool ApiSetupUtility::SetupMaster(const String& cn, bool prompt_restart)
|
|||
if (!SetupMasterApiUser())
|
||||
return false;
|
||||
|
||||
if (!SetupMasterEnableApi())
|
||||
if (!SetupMasterEnableApi(quiet))
|
||||
return false;
|
||||
|
||||
if (!SetupMasterUpdateConstants(cn))
|
||||
return false;
|
||||
|
||||
if (prompt_restart) {
|
||||
if (prompt_restart && !quiet) {
|
||||
std::cout << "Done.\n\n";
|
||||
std::cout << "Now restart your Icinga 2 daemon to finish the installation!\n\n";
|
||||
}
|
||||
|
@ -196,11 +196,11 @@ bool ApiSetupUtility::SetupMasterApiUser()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ApiSetupUtility::SetupMasterEnableApi()
|
||||
bool ApiSetupUtility::SetupMasterEnableApi(bool quiet)
|
||||
{
|
||||
Log(LogInformation, "cli", "Enabling the 'api' feature.");
|
||||
|
||||
FeatureUtility::EnableFeatures({ "api" });
|
||||
FeatureUtility::EnableFeatures({ "api" }, quiet);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -37,11 +37,11 @@ namespace icinga
|
|||
class ApiSetupUtility
|
||||
{
|
||||
public:
|
||||
static bool SetupMaster(const String& cn, bool prompt_restart = false);
|
||||
static bool SetupMaster(const String& cn, bool prompt_restart = false, bool quiet = false);
|
||||
|
||||
static bool SetupMasterCertificates(const String& cn);
|
||||
static bool SetupMasterApiUser();
|
||||
static bool SetupMasterEnableApi();
|
||||
static bool SetupMasterEnableApi(bool quiet = false);
|
||||
static bool SetupMasterUpdateConstants(const String& cn);
|
||||
|
||||
static String GetConfdPath();
|
||||
|
|
|
@ -56,7 +56,7 @@ std::vector<String> FeatureUtility::GetFieldCompletionSuggestions(const String&
|
|||
return suggestions;
|
||||
}
|
||||
|
||||
int FeatureUtility::EnableFeatures(const std::vector<std::string>& features)
|
||||
int FeatureUtility::EnableFeatures(const std::vector<std::string>& features, bool quiet)
|
||||
{
|
||||
String features_available_dir = GetFeaturesAvailablePath();
|
||||
String features_enabled_dir = GetFeaturesEnabledPath();
|
||||
|
@ -93,8 +93,9 @@ int FeatureUtility::EnableFeatures(const std::vector<std::string>& features)
|
|||
continue;
|
||||
}
|
||||
|
||||
std::cout << "Enabling feature " << ConsoleColorTag(Console_ForegroundMagenta | Console_Bold) << feature
|
||||
<< ConsoleColorTag(Console_Normal) << ". Make sure to restart Icinga 2 for these changes to take effect.\n";
|
||||
if (!quiet)
|
||||
std::cout << "Enabling feature " << ConsoleColorTag(Console_ForegroundMagenta | Console_Bold) << feature
|
||||
<< ConsoleColorTag(Console_Normal) << ". Make sure to restart Icinga 2 for these changes to take effect.\n";
|
||||
|
||||
#ifndef _WIN32
|
||||
String relativeSource = "../features-available/" + feature + ".conf";
|
||||
|
@ -131,7 +132,7 @@ int FeatureUtility::EnableFeatures(const std::vector<std::string>& features)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int FeatureUtility::DisableFeatures(const std::vector<std::string>& features)
|
||||
int FeatureUtility::DisableFeatures(const std::vector<std::string>& features, bool quiet)
|
||||
{
|
||||
String features_enabled_dir = GetFeaturesEnabledPath();
|
||||
|
||||
|
@ -160,8 +161,9 @@ int FeatureUtility::DisableFeatures(const std::vector<std::string>& features)
|
|||
continue;
|
||||
}
|
||||
|
||||
std::cout << "Disabling feature " << ConsoleColorTag(Console_ForegroundMagenta | Console_Bold) << feature
|
||||
<< ConsoleColorTag(Console_Normal) << ". Make sure to restart Icinga 2 for these changes to take effect.\n";
|
||||
if (!quiet)
|
||||
std::cout << "Disabling feature " << ConsoleColorTag(Console_ForegroundMagenta | Console_Bold) << feature
|
||||
<< ConsoleColorTag(Console_Normal) << ". Make sure to restart Icinga 2 for these changes to take effect.\n";
|
||||
}
|
||||
|
||||
if (!errors.empty()) {
|
||||
|
|
|
@ -40,8 +40,8 @@ public:
|
|||
|
||||
static std::vector<String> GetFieldCompletionSuggestions(const String& word, bool enable);
|
||||
|
||||
static int EnableFeatures(const std::vector<std::string>& features);
|
||||
static int DisableFeatures(const std::vector<std::string>& features);
|
||||
static int EnableFeatures(const std::vector<std::string>& features, bool quiet = false);
|
||||
static int DisableFeatures(const std::vector<std::string>& features, bool quiet = false);
|
||||
static int ListFeatures(std::ostream& os = std::cout);
|
||||
|
||||
static bool GetFeatures(std::vector<String>& features, bool enable);
|
||||
|
|
|
@ -224,11 +224,23 @@ void ApiListener::Start(bool runtimeCreated)
|
|||
OpenLogFile();
|
||||
}
|
||||
|
||||
/* create the primary JSON-RPC listener */
|
||||
if (!AddListener(GetBindHost(), GetBindPort())) {
|
||||
Log(LogCritical, "ApiListener")
|
||||
<< "Cannot add listener on host '" << GetBindHost() << "' for port '" << GetBindPort() << "'.";
|
||||
Application::Exit(EXIT_FAILURE);
|
||||
Dictionary::Ptr envData = ScriptGlobal::Get("EnvironmentInfo", &Empty);
|
||||
if (envData) {
|
||||
ScriptGlobal::Set("EnvironmentInfo", Empty);
|
||||
TcpSocket::Ptr listener = envData->Get("listener");
|
||||
if (!AddListener(listener)) {
|
||||
Log(LogCritical, "ApiListener")
|
||||
<< "Failed to set up pre-configured agent listener.";
|
||||
Application::Exit(EXIT_FAILURE);
|
||||
}
|
||||
Utility::SaveJsonFile(envData->Get("meta_path"), 0600, envData->Get("config"));
|
||||
} else {
|
||||
/* create the primary JSON-RPC listener */
|
||||
if (!AddListener(GetBindHost(), GetBindPort())) {
|
||||
Log(LogCritical, "ApiListener")
|
||||
<< "Cannot add listener on host '" << GetBindHost() << "' for port '" << GetBindPort() << "'.";
|
||||
Application::Exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
m_Timer = new Timer();
|
||||
|
@ -301,6 +313,33 @@ bool ApiListener::IsMaster() const
|
|||
return master == GetLocalEndpoint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new JSON-RPC listener using the specified TCP socket object.
|
||||
*
|
||||
* @param listener The TCP socket to use.
|
||||
*/
|
||||
bool ApiListener::AddListener(const TcpSocket::Ptr& listener)
|
||||
{
|
||||
ObjectLock olock(this);
|
||||
|
||||
std::shared_ptr<SSL_CTX> sslContext = m_SSLContext;
|
||||
|
||||
if (!sslContext) {
|
||||
Log(LogCritical, "ApiListener", "SSL context is required for AddListener()");
|
||||
return false;
|
||||
}
|
||||
|
||||
Log(LogInformation, "ApiListener")
|
||||
<< "Adding pre-configured listener on address " << listener->GetClientAddress();
|
||||
|
||||
std::thread thread(std::bind(&ApiListener::ListenerThreadProc, this, listener));
|
||||
thread.detach();
|
||||
|
||||
m_Servers.insert(listener);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new JSON-RPC listener on the specified port.
|
||||
*
|
||||
|
|
|
@ -138,6 +138,7 @@ private:
|
|||
void CleanupCertificateRequestsTimerHandler();
|
||||
|
||||
bool AddListener(const String& node, const String& service);
|
||||
bool AddListener(const TcpSocket::Ptr& listener);
|
||||
void AddConnection(const Endpoint::Ptr& endpoint);
|
||||
|
||||
void NewClientHandler(const Socket::Ptr& client, const String& hostname, ConnectionRole role);
|
||||
|
|
Loading…
Reference in New Issue