From 1236495dd3c1bbfb2a9f413a5c9cf497e4fca26e Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Thu, 25 Aug 2016 19:14:54 +0200 Subject: [PATCH] Implement the --file and --syntax-only options for "icinga2 console" fixes #12554 fixes #10675 --- doc/11-cli-commands.md | 4 +++- lib/cli/consolecommand.cpp | 42 +++++++++++++++++++++++++++++++++----- lib/cli/consolecommand.hpp | 2 +- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/doc/11-cli-commands.md b/doc/11-cli-commands.md index 5a36d86e2..31fea0ff4 100644 --- a/doc/11-cli-commands.md +++ b/doc/11-cli-commands.md @@ -214,7 +214,9 @@ Once connected you can inspect variables and execute other expressions by enteri <3> => -You can use the `--eval` parameter to evaluate a single expression in batch mode. The output format for batch mode is JSON. +You can use the `--eval` parameter to evaluate a single expression in batch mode. Using the `--file` option you can specify a file which should be evaluated. The output format for batch mode is JSON. + +The `--syntax-only` option can be used in combination with `--eval` or `--file` to check a script for syntax errors. In this mode the script is parsed to identify syntax errors but not evaluated. Here's an example that retrieves the command that was used by Icinga to check the `example.localdomain` host: diff --git a/lib/cli/consolecommand.cpp b/lib/cli/consolecommand.cpp index ed7b37e25..421e9fd2c 100644 --- a/lib/cli/consolecommand.cpp +++ b/lib/cli/consolecommand.cpp @@ -138,6 +138,8 @@ void ConsoleCommand::InitParameters(boost::program_options::options_description& visibleDesc.add_options() ("connect,c", po::value(), "connect to an Icinga 2 instance") ("eval,e", po::value(), "evaluate expression and terminate") + ("file,r", po::value(), "evaluate a file and terminate") + ("syntax-only", "only validate syntax (requires --eval or --file)") ("sandbox", "enable sandbox mode") ; } @@ -204,7 +206,7 @@ int ConsoleCommand::Run(const po::variables_map& vm, const std::vector(); String command; + bool syntaxOnly = false; + + if (vm.count("syntax-only")) { + if (vm.count("eval") || vm.count("file")) + syntaxOnly = true; + else { + std::cerr << "The option --syntax-only can only be used in combination with --eval or --file." << std::endl; + return EXIT_FAILURE; + } + } if (vm.count("eval")) command = vm["eval"].as(); + else if (vm.count("file")) { + std::string fname = vm["file"].as(); - return RunScriptConsole(scriptFrame, addr, session, command);; + try { + std::ifstream fp(fname.c_str()); + fp.exceptions(std::ifstream::failbit | std::ifstream::badbit); + command = String(std::istreambuf_iterator(fp), std::istreambuf_iterator()); + } catch (const std::exception&) { + std::cerr << "Could not read file '" << fname << "'." << std::endl; + return EXIT_FAILURE; + } + } + + return RunScriptConsole(scriptFrame, addr, session, command, syntaxOnly); } -int ConsoleCommand::RunScriptConsole(ScriptFrame& scriptFrame, const String& addr, const String& session, const String& commandOnce) +int ConsoleCommand::RunScriptConsole(ScriptFrame& scriptFrame, const String& addr, const String& session, const String& commandOnce, bool syntaxOnly) { std::map lines; int next_line = 1; @@ -341,7 +365,15 @@ incomplete: if (!l_ApiClient) { expr = ConfigCompiler::CompileText(fileName, command); - result = Serialize(expr->Evaluate(scriptFrame), 0); + + /* This relies on the fact that - for syntax errors - CompileText() + * returns an AST where the top-level expression is a 'throw'. */ + if (!syntaxOnly || dynamic_cast(expr)) { + if (syntaxOnly) + std::cerr << " => " << command << std::endl; + result = Serialize(expr->Evaluate(scriptFrame), 0); + } else + result = true; } else { boost::mutex mutex; boost::condition_variable cv; @@ -373,7 +405,7 @@ incomplete: break; } } catch (const ScriptError& ex) { - if (ex.IsIncompleteExpression()) { + if (ex.IsIncompleteExpression() && commandOnce.IsEmpty()) { continuation = true; goto incomplete; } diff --git a/lib/cli/consolecommand.hpp b/lib/cli/consolecommand.hpp index 978848e04..331f226a4 100644 --- a/lib/cli/consolecommand.hpp +++ b/lib/cli/consolecommand.hpp @@ -47,7 +47,7 @@ public: virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; static int RunScriptConsole(ScriptFrame& scriptFrame, const String& addr = String(), - const String& session = String(), const String& commandOnce = String()); + const String& session = String(), const String& commandOnce = String(), bool syntaxOnly = false); private: mutable boost::mutex m_Mutex;