Example #1
0
MainForm::MainForm(wxWindow *parent, const Url::Ptr& url)
	: MainFormBase(parent)
{
#ifdef _WIN32
	SetIcon(wxICON(icinga));
	SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
#endif /* _WIN32 */

	String port = url->GetPort();

	if (port.IsEmpty())
		port = "5665";

	m_ApiClient = new ApiClient(url->GetHost(), port, url->GetUsername(), url->GetPassword());
	m_ApiClient->GetTypes(boost::bind(&MainForm::TypesCompletionHandler, this, _1, _2, true));

	std::string title = url->Format() + " - Icinga Studio";
	SetTitle(title);

	m_ObjectsList->InsertColumn(0, "Name", 0, 300);
	
	m_PropertyGrid->SetColumnCount(3);
}
Example #2
0
/**
 * Sends the request via REST API and returns the parsed response.
 *
 * @param tlsStream Caller must prepare TLS stream/handshake.
 * @param url Fully prepared Url object.
 * @return A dictionary decoded from JSON.
 */
Dictionary::Ptr ConsoleCommand::SendRequest()
{
	namespace beast = boost::beast;
	namespace http = beast::http;

	l_TlsStream = ConsoleCommand::Connect();

	Defer s ([&]() {
		l_TlsStream->next_layer().shutdown();
	});

	http::request<http::string_body> request(http::verb::post, std::string(l_Url->Format(false)), 10);

	request.set(http::field::user_agent, "Icinga/DebugConsole/" + Application::GetAppVersion());
	request.set(http::field::host, l_Url->GetHost() + ":" + l_Url->GetPort());

	request.set(http::field::accept, "application/json");
	request.set(http::field::authorization, "Basic " + Base64::Encode(l_Url->GetUsername() + ":" + l_Url->GetPassword()));

	try {
		http::write(*l_TlsStream, request);
		l_TlsStream->flush();
	} catch (const std::exception &ex) {
		Log(LogWarning, "DebugConsole")
			<< "Cannot write HTTP request to REST API at URL '" << l_Url->Format(true) << "': " << ex.what();
		throw;
	}

	http::parser<false, http::string_body> parser;
	beast::flat_buffer buf;

	try {
		http::read(*l_TlsStream, buf, parser);
	} catch (const std::exception &ex) {
		Log(LogWarning, "DebugConsole")
			<< "Failed to parse HTTP response from REST API at URL '" << l_Url->Format(true) << "': " << ex.what();
		throw;
	}

	auto &response(parser.get());

	/* Handle HTTP errors first. */
	if (response.result() != http::status::ok) {
		String message = "HTTP request failed; Code: " + Convert::ToString(response.result())
			+ "; Body: " + response.body();
		BOOST_THROW_EXCEPTION(ScriptError(message));
	}

	Dictionary::Ptr jsonResponse;
	auto &body(response.body());

	//Log(LogWarning, "Console")
	//	<< "Got response: " << response.body();

	try {
		jsonResponse = JsonDecode(body);
	} catch (...) {
		String message = "Cannot parse JSON response body: " + response.body();
		BOOST_THROW_EXCEPTION(ScriptError(message));
	}

	return jsonResponse;
}
Example #3
0
int ConsoleCommand::RunScriptConsole(ScriptFrame& scriptFrame, const String& addr, const String& session, const String& commandOnce, const String& commandOnceFileName, bool syntaxOnly)
{
	std::map<String, String> lines;
	int next_line = 1;

#ifdef HAVE_EDITLINE
	char *homeEnv = getenv("HOME");

	String historyPath;
	std::fstream historyfp;

	if (homeEnv) {
		historyPath = String(homeEnv) + "/.icinga2_history";

		historyfp.open(historyPath.CStr(), std::fstream::in);

		String line;
		while (std::getline(historyfp, line.GetData()))
			add_history(line.CStr());

		historyfp.close();
	}
#endif /* HAVE_EDITLINE */

	l_ScriptFrame = &scriptFrame;
	l_Session = session;

	if (!addr.IsEmpty()) {
		Url::Ptr url;

		try {
			url = new Url(addr);
		} catch (const std::exception& ex) {
			Log(LogCritical, "ConsoleCommand", ex.what());
			return EXIT_FAILURE;
		}

		const char *usernameEnv = getenv("ICINGA2_API_USERNAME");
		const char *passwordEnv = getenv("ICINGA2_API_PASSWORD");

		if (usernameEnv)
			url->SetUsername(usernameEnv);
		if (passwordEnv)
			url->SetPassword(passwordEnv);

		if (url->GetPort().IsEmpty())
			url->SetPort("5665");

		l_ApiClient = new ApiClient(url->GetHost(), url->GetPort(), url->GetUsername(), url->GetPassword());
	}

	while (std::cin.good()) {
		String fileName;

		if (commandOnceFileName.IsEmpty())
			fileName = "<" + Convert::ToString(next_line) + ">";
		else
			fileName = commandOnceFileName;

		next_line++;

		bool continuation = false;
		std::string command;

incomplete:
		std::string line;

		if (commandOnce.IsEmpty()) {
#ifdef HAVE_EDITLINE
			std::ostringstream promptbuf;
			std::ostream& os = promptbuf;
#else /* HAVE_EDITLINE */
			std::ostream& os = std::cout;
#endif /* HAVE_EDITLINE */

			os << fileName;

			if (!continuation)
				os << " => ";
			else
				os << " .. ";

#ifdef HAVE_EDITLINE
			String prompt = promptbuf.str();

			char *cline;
			cline = readline(prompt.CStr());

			if (!cline)
				break;

			if (commandOnce.IsEmpty() && cline[0] != '\0') {
				add_history(cline);

				if (!historyPath.IsEmpty()) {
					historyfp.open(historyPath.CStr(), std::fstream::out | std::fstream::app);
					historyfp << cline << "\n";
					historyfp.close();
				}
			}

			line = cline;

			free(cline);
#else /* HAVE_EDITLINE */
			std::getline(std::cin, line);
#endif /* HAVE_EDITLINE */
		} else
			line = commandOnce;

		if (!line.empty() && line[0] == '$') {
			if (line == "$continue" || line == "$quit" || line == "$exit")
				break;
			else if (line == "$help")
				std::cout << "Welcome to the Icinga 2 debug console.\n"
					"Usable commands:\n"
					"  $continue      Continue running Icinga 2 (script debugger).\n"
					"  $quit, $exit   Stop debugging and quit the console.\n"
					"  $help          Print this help.\n\n"
					"For more information on how to use this console, please consult the documentation at https://icinga.com/docs\n";
			else
				std::cout << "Unknown debugger command: " << line << "\n";

			continue;
		}

		if (!command.empty())
			command += "\n";

		command += line;

		std::unique_ptr<Expression> expr;

		try {
			lines[fileName] = command;

			Value result;

			if (!l_ApiClient) {
				expr = ConfigCompiler::CompileText(fileName, command);

				/* 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<ThrowExpression *>(expr.get())) {
					if (syntaxOnly)
						std::cerr << "    => " << command << std::endl;
					result = Serialize(expr->Evaluate(scriptFrame), 0);
				} else
					result = true;
			} else {
				boost::mutex mutex;
				boost::condition_variable cv;
				bool ready = false;
				boost::exception_ptr eptr;

				l_ApiClient->ExecuteScript(l_Session, command, scriptFrame.Sandboxed,
					std::bind(&ConsoleCommand::ExecuteScriptCompletionHandler,
					std::ref(mutex), std::ref(cv), std::ref(ready),
					_1, _2,
					std::ref(result), std::ref(eptr)));

				{
					boost::mutex::scoped_lock lock(mutex);
					while (!ready)
						cv.wait(lock);
				}

				if (eptr)
					boost::rethrow_exception(eptr);
			}

			if (commandOnce.IsEmpty()) {
				std::cout << ConsoleColorTag(Console_ForegroundCyan);
				ConfigWriter::EmitValue(std::cout, 1, result);
				std::cout << ConsoleColorTag(Console_Normal) << "\n";
			} else {
				std::cout << JsonEncode(result) << "\n";
				break;
			}
		} catch (const ScriptError& ex) {
			if (ex.IsIncompleteExpression() && commandOnce.IsEmpty()) {
				continuation = true;
				goto incomplete;
			}

			DebugInfo di = ex.GetDebugInfo();

			if (commandOnceFileName.IsEmpty() && lines.find(di.Path) != lines.end()) {
				String text = lines[di.Path];

				std::vector<String> ulines = text.Split("\n");

				for (int i = 1; i <= ulines.size(); i++) {
					int start, len;

					if (i == di.FirstLine)
						start = di.FirstColumn;
					else
						start = 0;

					if (i == di.LastLine)
						len = di.LastColumn - di.FirstColumn + 1;
					else
						len = ulines[i - 1].GetLength();

					int offset;

					if (di.Path != fileName) {
						std::cout << di.Path << ": " << ulines[i - 1] << "\n";
						offset = 2;
					} else
						offset = 4;

					if (i >= di.FirstLine && i <= di.LastLine) {
						std::cout << String(di.Path.GetLength() + offset, ' ');
						std::cout << String(start, ' ') << String(len, '^') << "\n";
					}
				}
			} else {
				ShowCodeLocation(std::cout, di);
			}

			std::cout << ex.what() << "\n";

			if (!commandOnce.IsEmpty())
				return EXIT_FAILURE;
		} catch (const std::exception& ex) {
			std::cout << "Error: " << DiagnosticInformation(ex) << "\n";

			if (!commandOnce.IsEmpty())
				return EXIT_FAILURE;
		}
	}

	return EXIT_SUCCESS;
}