]> granicus.if.org Git - icinga2/commitdiff
Implement the "variable" CLI command
authorGunnar Beutner <gunnar@beutner.name>
Mon, 20 Oct 2014 19:14:00 +0000 (21:14 +0200)
committerGunnar Beutner <gunnar@beutner.name>
Mon, 20 Oct 2014 19:14:56 +0000 (21:14 +0200)
fixes #7370

icinga-app/icinga.cpp
lib/base/application.cpp
lib/base/application.hpp
lib/base/scriptvariable.cpp
lib/base/scriptvariable.hpp
lib/cli/CMakeLists.txt
lib/cli/daemoncommand.cpp
lib/cli/variablegetcommand.cpp [new file with mode: 0644]
lib/cli/variablegetcommand.hpp [new file with mode: 0644]
lib/cli/variablelistcommand.cpp [new file with mode: 0644]
lib/cli/variablelistcommand.hpp [new file with mode: 0644]

index 4469fbbae9ddc6e5559d073c03ae588691089d62..479c09f2b2ce0b2cdeb50ed608fb456968efa90d 100644 (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());
index 772a71e4045d78f6c7c6fca9a5668bc440a87efe..24c48d0b409363f898dfbdeb104a3c5d975c3305 100644 (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.
  *
index eb37138468335d613a03923825a48f95a57b6dd3..ac5becb0da7643e30600b0c58c0680f9d243eb0e 100644 (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);
 
index 5174ad5eb54ec49e347870015f45cd8b4e244cdd..ef131fb50c2565f268391dbe2350ca84e5678847 100644 (file)
 
 #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();
index 491e8b05a90c948956dd07a7acacbb5185d9cd38..602c524c084a8354be003055aea2a92225b9d6af 100644 (file)
 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 */
index 1e8a87573d6a9b80027dc015493abf196c25db65..104e109f0f97e030d780cc819d33703feccbbee6 100644 (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)
index f5e6de2974a34a869c30bd2ce14b46f42d314edc..0fe56ebc85d3bf471121443576514c79e9c41f45 100644 (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")) {
diff --git a/lib/cli/variablegetcommand.cpp b/lib/cli/variablegetcommand.cpp
new file mode 100644 (file)
index 0000000..f920e50
--- /dev/null
@@ -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;
+}
diff --git a/lib/cli/variablegetcommand.hpp b/lib/cli/variablegetcommand.hpp
new file mode 100644 (file)
index 0000000..25c0304
--- /dev/null
@@ -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 */
diff --git a/lib/cli/variablelistcommand.cpp b/lib/cli/variablelistcommand.cpp
new file mode 100644 (file)
index 0000000..a5382ac
--- /dev/null
@@ -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";
+}
diff --git a/lib/cli/variablelistcommand.hpp b/lib/cli/variablelistcommand.hpp
new file mode 100644 (file)
index 0000000..4ec2d3b
--- /dev/null
@@ -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 */