Implement the "variable" CLI command

fixes #7370
This commit is contained in:
Gunnar Beutner 2014-10-20 21:14:00 +02:00
parent 7d2f60a00e
commit 2972c6bfe8
11 changed files with 406 additions and 8 deletions

View File

@ -228,6 +228,7 @@ int Main(void)
Application::DeclareStatePath(Application::GetLocalStateDir() + "/lib/icinga2/icinga2.state");
Application::DeclareObjectsPath(Application::GetLocalStateDir() + "/cache/icinga2/icinga2.debug");
Application::DeclareVarsPath(Application::GetLocalStateDir() + "/cache/icinga2/icinga2.vars");
Application::DeclarePidPath(Application::GetRunDir() + "/icinga2/icinga2.pid");
ConfigCompiler::AddIncludeSearchDir(Application::GetIncludeConfDir());

View File

@ -481,6 +481,7 @@ void Application::DisplayInfoMessage(bool skipVersion)
<< " Package data directory: " << GetPkgDataDir() << std::endl
<< " State path: " << GetStatePath() << std::endl
<< " Objects path: " << GetObjectsPath() << std::endl
<< " Vars path: " << GetVarsPath() << std::endl
<< " PID path: " << GetPidPath() << std::endl
<< " Application type: " << GetApplicationType() << std::endl;
}
@ -1012,6 +1013,26 @@ void Application::DeclareObjectsPath(const String& path)
ScriptVariable::Set("ObjectsPath", path, false);
}
/**
* Retrieves the path for the vars file.
*
* @returns The path.
*/
String Application::GetVarsPath(void)
{
return ScriptVariable::Get("VarsPath", &Empty);
}
/**
* Sets the path for the vars file.
*
* @param path The new path.
*/
void Application::DeclareVarsPath(const String& path)
{
ScriptVariable::Set("VarsPath", path, false);
}
/**
* Retrieves the path for the PID file.
*

View File

@ -107,6 +107,9 @@ public:
static String GetObjectsPath(void);
static void DeclareObjectsPath(const String& path);
static String GetVarsPath(void);
static void DeclareVarsPath(const String& path);
static String GetPidPath(void);
static void DeclarePidPath(const String& path);

View File

@ -19,6 +19,12 @@
#include "base/scriptvariable.hpp"
#include "base/singleton.hpp"
#include "base/logger.hpp"
#include "base/stdiostream.hpp"
#include "base/netstring.hpp"
#include "base/convert.hpp"
#include <boost/foreach.hpp>
#include <fstream>
using namespace icinga;
@ -90,6 +96,55 @@ void ScriptVariable::Unregister(const String& name)
ScriptVariableRegistry::GetInstance()->Unregister(name);
}
void ScriptVariable::WriteVariablesFile(const String& filename)
{
Log(LogInformation, "ScriptVariable")
<< "Dumping variables to file '" << filename << "'";
String tempFilename = filename + ".tmp";
std::fstream fp;
fp.open(tempFilename.CStr(), std::ios_base::out);
if (!fp)
BOOST_THROW_EXCEPTION(std::runtime_error("Could not open '" + tempFilename + "' file"));
StdioStream::Ptr sfp = make_shared<StdioStream>(&fp, false);
BOOST_FOREACH(const ScriptVariableRegistry::ItemMap::value_type& kv, ScriptVariableRegistry::GetInstance()->GetItems()) {
Dictionary::Ptr persistentVariable = make_shared<Dictionary>();
persistentVariable->Set("name", kv.first);
ScriptVariable::Ptr sv = kv.second;
Value value = sv->GetData();
if (value.IsObject())
value = Convert::ToString(value);
persistentVariable->Set("value", value);
String json = JsonSerialize(persistentVariable);
NetString::WriteStringToStream(sfp, json);
}
sfp->Close();
fp.close();
#ifdef _WIN32
_unlink(filename.CStr());
#endif /* _WIN32 */
if (rename(tempFilename.CStr(), filename.CStr()) < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("rename")
<< boost::errinfo_errno(errno)
<< boost::errinfo_file_name(tempFilename));
}
}
ScriptVariableRegistry *ScriptVariableRegistry::GetInstance(void)
{
return Singleton<ScriptVariableRegistry>::GetInstance();

View File

@ -27,6 +27,14 @@
namespace icinga
{
class ScriptVariable;
class I2_BASE_API ScriptVariableRegistry : public Registry<ScriptVariableRegistry, shared_ptr<ScriptVariable> >
{
public:
static ScriptVariableRegistry *GetInstance(void);
};
/**
* A script variables.
*
@ -51,17 +59,13 @@ public:
static Value Get(const String& name, const Value *defaultValue = NULL);
static ScriptVariable::Ptr Set(const String& name, const Value& value, bool overwrite = true, bool make_const = false);
static void WriteVariablesFile(const String& filename);
private:
Value m_Data;
bool m_Constant;
};
class I2_BASE_API ScriptVariableRegistry : public Registry<ScriptVariableRegistry, ScriptVariable::Ptr>
{
public:
static ScriptVariableRegistry *GetInstance(void);
};
}
#endif /* SCRIPTVARIABLE_H */

View File

@ -24,6 +24,7 @@ set(cli_SOURCES
objectlistcommand.cpp
pkinewcacommand.cpp pkinewcertcommand.cpp pkisigncsrcommand.cpp pkirequestcommand.cpp pkiticketcommand.cpp
repositoryobjectcommand.cpp
variablegetcommand.cpp variablelistcommand.cpp
)
if(ICINGA2_UNITY_BUILD)

View File

@ -76,7 +76,8 @@ static void IncludeNonLocalZone(const String& zonePath)
IncludeZoneDirRecursive(zonePath);
}
static bool LoadConfigFiles(const boost::program_options::variables_map& vm, const String& appType, const String& objectsFile = String())
static bool LoadConfigFiles(const boost::program_options::variables_map& vm, const String& appType,
const String& objectsFile = String(), const String& varsfile = String())
{
ConfigCompilerContext::GetInstance()->Reset();
@ -148,6 +149,8 @@ static bool LoadConfigFiles(const boost::program_options::variables_map& vm, con
if (!result)
return false;
ScriptVariable::WriteVariablesFile(varsfile);
return true;
}
@ -327,7 +330,7 @@ int DaemonCommand::Run(const po::variables_map& vm, const std::vector<std::strin
}
}
if (!LoadConfigFiles(vm, appType, Application::GetObjectsPath()))
if (!LoadConfigFiles(vm, appType, Application::GetObjectsPath(), Application::GetVarsPath()))
return EXIT_FAILURE;
if (vm.count("validate")) {

View File

@ -0,0 +1,108 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#include "cli/variablegetcommand.hpp"
#include "base/logger.hpp"
#include "base/application.hpp"
#include "base/convert.hpp"
#include "base/dynamicobject.hpp"
#include "base/dynamictype.hpp"
#include "base/serializer.hpp"
#include "base/netstring.hpp"
#include "base/stdiostream.hpp"
#include "base/debug.hpp"
#include "base/objectlock.hpp"
#include "base/console.hpp"
#include "base/scriptvariable.hpp"
#include <boost/foreach.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <fstream>
#include <iostream>
using namespace icinga;
namespace po = boost::program_options;
REGISTER_CLICOMMAND("variable/get", VariableGetCommand);
String VariableGetCommand::GetDescription(void) const
{
return "Prints the value of an Icinga 2 variable.";
}
String VariableGetCommand::GetShortDescription(void) const
{
return "gets a variable";
}
void VariableGetCommand::InitParameters(boost::program_options::options_description& visibleDesc,
boost::program_options::options_description& hiddenDesc) const
{
visibleDesc.add_options()
("current", "Uses the current value (i.e. from the running process, rather than from the vars file)");
}
/**
* The entry point for the "variable get" CLI command.
*
* @returns An exit status.
*/
int VariableGetCommand::Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const
{
if (ap.size() != 1) {
Log(LogCritical, "cli", "Missing argument: variable name");
return 1;
}
if (vm.count("current")) {
std::cout << ScriptVariable::Get(ap[0], &Empty);
return 0;
}
String varsfile = Application::GetVarsPath();
if (!Utility::PathExists(varsfile)) {
Log(LogCritical, "cli")
<< "Cannot open variables file '" << varsfile << "'.";
Log(LogCritical, "cli", "Run 'icinga2 daemon -C' to validate config and generate the cache file.");
return 1;
}
std::fstream fp;
fp.open(varsfile.CStr(), std::ios_base::in);
StdioStream::Ptr sfp = make_shared<StdioStream>(&fp, false);
unsigned long variables_count = 0;
String message;
while (NetString::ReadStringFromStream(sfp, &message)) {
Dictionary::Ptr variable = JsonDeserialize(message);
if (variable->Get("name") == ap[0]) {
std::cout << variable->Get("value");
break;
}
}
sfp->Close();
fp.close();
return 0;
}

View File

@ -0,0 +1,50 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#ifndef VARIABLEGETCOMMAND_H
#define VARIABLEGETCOMMAND_H
#include "base/dictionary.hpp"
#include "base/array.hpp"
#include "cli/clicommand.hpp"
#include <ostream>
namespace icinga
{
/**
* The "variable get" command.
*
* @ingroup cli
*/
class VariableGetCommand : public CLICommand
{
public:
DECLARE_PTR_TYPEDEFS(VariableGetCommand);
virtual String GetDescription(void) const;
virtual String GetShortDescription(void) const;
void InitParameters(boost::program_options::options_description& visibleDesc,
boost::program_options::options_description& hiddenDesc) const;
virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const;
};
}
#endif /* VARIABLEGETCOMMAND_H */

View File

@ -0,0 +1,101 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#include "cli/variablelistcommand.hpp"
#include "base/logger.hpp"
#include "base/application.hpp"
#include "base/convert.hpp"
#include "base/dynamicobject.hpp"
#include "base/dynamictype.hpp"
#include "base/serializer.hpp"
#include "base/netstring.hpp"
#include "base/stdiostream.hpp"
#include "base/debug.hpp"
#include "base/objectlock.hpp"
#include "base/console.hpp"
#include <boost/foreach.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <fstream>
#include <iostream>
using namespace icinga;
namespace po = boost::program_options;
REGISTER_CLICOMMAND("variable/list", VariableListCommand);
String VariableListCommand::GetDescription(void) const
{
return "Lists all Icinga 2 variables.";
}
String VariableListCommand::GetShortDescription(void) const
{
return "lists all variables";
}
/**
* The entry point for the "variable list" CLI command.
*
* @returns An exit status.
*/
int VariableListCommand::Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const
{
if (!ap.empty()) {
Log(LogWarning, "cli")
<< "Ignoring parameters: " << boost::algorithm::join(ap, " ");
}
String varsfile = Application::GetVarsPath();
if (!Utility::PathExists(varsfile)) {
Log(LogCritical, "cli")
<< "Cannot open variables file '" << varsfile << "'.";
Log(LogCritical, "cli", "Run 'icinga2 daemon -C' to validate config and generate the cache file.");
return 1;
}
std::fstream fp;
fp.open(varsfile.CStr(), std::ios_base::in);
StdioStream::Ptr sfp = make_shared<StdioStream>(&fp, false);
unsigned long variables_count = 0;
String message;
while (NetString::ReadStringFromStream(sfp, &message)) {
PrintVariable(std::cout, message);
variables_count++;
}
sfp->Close();
fp.close();
Log(LogNotice, "cli")
<< "Parsed " << variables_count << " variables.";
return 0;
}
void VariableListCommand::PrintVariable(std::ostream& fp, const String& message)
{
Dictionary::Ptr variable = JsonDeserialize(message);
std::cout << variable->Get("name") << " = " << variable->Get("value") << "\n";
}

View File

@ -0,0 +1,51 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#ifndef VARIABLELISTCOMMAND_H
#define VARIABLELISTCOMMAND_H
#include "base/dictionary.hpp"
#include "base/array.hpp"
#include "cli/clicommand.hpp"
#include <ostream>
namespace icinga
{
/**
* The "variable list" command.
*
* @ingroup cli
*/
class VariableListCommand : public CLICommand
{
public:
DECLARE_PTR_TYPEDEFS(VariableListCommand);
virtual String GetDescription(void) const;
virtual String GetShortDescription(void) const;
virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const;
private:
static void PrintVariable(std::ostream& fp, const String& message);
};
}
#endif /* VARIABLELISTCOMMAND_H */