Exemple #1
0
Value CheckerComponent::StatsFunc(Dictionary::Ptr& status, Dictionary::Ptr& perfdata)
{
	Dictionary::Ptr nodes = make_shared<Dictionary>();

	BOOST_FOREACH(const CheckerComponent::Ptr& checker, DynamicType::GetObjects<CheckerComponent>()) {
		unsigned long idle = checker->GetIdleServices();
		unsigned long pending = checker->GetPendingServices();

		Dictionary::Ptr stats = make_shared<Dictionary>();
		stats->Set("idle", idle);
		stats->Set("pending", pending);

		nodes->Set(checker->GetName(), stats);

		String perfdata_prefix = "checkercomponent_" + checker->GetName() + "_";
		perfdata->Set(perfdata_prefix + "idle", Convert::ToDouble(idle));
		perfdata->Set(perfdata_prefix + "pending", Convert::ToDouble(pending));
	}
Exemple #2
0
void ClusterEvents::NextNotificationChangedHandler(const Notification::Ptr& notification, const MessageOrigin::Ptr& origin)
{
	ApiListener::Ptr listener = ApiListener::GetInstance();

	if (!listener)
		return;

	Dictionary::Ptr params = new Dictionary();
	params->Set("notification", notification->GetName());
	params->Set("next_notification", notification->GetNextNotification());

	Dictionary::Ptr message = new Dictionary();
	message->Set("jsonrpc", "2.0");
	message->Set("method", "event::SetNextNotification");
	message->Set("params", params);

	listener->RelayMessage(origin, notification, message, true);
}
Exemple #3
0
void ClusterEvents::SendNotificationsHandler(const Checkable::Ptr& checkable, NotificationType type,
	const CheckResult::Ptr& cr, const String& author, const String& text, const MessageOrigin::Ptr& origin)
{
	ApiListener::Ptr listener = ApiListener::GetInstance();

	if (!listener)
		return;

	Dictionary::Ptr message = MakeCheckResultMessage(checkable, cr);
	message->Set("method", "event::SendNotifications");

	Dictionary::Ptr params = message->Get("params");
	params->Set("type", type);
	params->Set("author", author);
	params->Set("text", text);

	listener->RelayMessage(origin, nullptr, message, true);
}
Exemple #4
0
void CheckerComponent::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata)
{
	DictionaryData nodes;

	for (const CheckerComponent::Ptr& checker : ConfigType::GetObjectsByType<CheckerComponent>()) {
		unsigned long idle = checker->GetIdleCheckables();
		unsigned long pending = checker->GetPendingCheckables();

		nodes.emplace_back(checker->GetName(), new Dictionary({
			{ "idle", idle },
			{ "pending", pending }
		}));

		String perfdata_prefix = "checkercomponent_" + checker->GetName() + "_";
		perfdata->Add(new PerfdataValue(perfdata_prefix + "idle", Convert::ToDouble(idle)));
		perfdata->Add(new PerfdataValue(perfdata_prefix + "pending", Convert::ToDouble(pending)));
	}

	status->Set("checkercomponent", new Dictionary(std::move(nodes)));
}
Exemple #5
0
void ApiClient::SendMessageSync(const Dictionary::Ptr& message)
{
	try {
		ObjectLock olock(m_Stream);
		if (m_Stream->IsEof())
			return;
		JsonRpc::SendMessage(m_Stream, message);
		if (message->Get("method") != "log::SetLogPosition")
			m_Seen = Utility::GetTime();
	} catch (const std::exception& ex) {
		std::ostringstream info;
		info << "Error while sending JSON-RPC message for identity '" << m_Identity << "'";
		Log(LogWarning, "ApiClient")
		    << info.str();
		Log(LogDebug, "ApiClient")
		    << info.str() << "\n" << DiagnosticInformation(ex);

		Disconnect();
	}
}
String Comment::AddComment(const Checkable::Ptr& checkable, CommentType entryType, const String& author,
    const String& text, double expireTime, const String& id, const MessageOrigin::Ptr& origin)
{
	String fullName;

	if (id.IsEmpty())
		fullName = checkable->GetName() + "!" + Utility::NewUniqueID();
	else
		fullName = id;

	Dictionary::Ptr attrs = new Dictionary();

	attrs->Set("author", author);
	attrs->Set("text", text);
	attrs->Set("expire_time", expireTime);
	attrs->Set("entry_type", entryType);

	Host::Ptr host;
	Service::Ptr service;
	tie(host, service) = GetHostService(checkable);

	attrs->Set("host_name", host->GetName());
	if (service)
		attrs->Set("service_name", service->GetShortName());

	String zone = checkable->GetZoneName();

	if (!zone.IsEmpty())
		attrs->Set("zone", zone);

	String config = ConfigObjectUtility::CreateObjectConfig(Comment::TypeInstance, fullName, true, Array::Ptr(), attrs);

	Array::Ptr errors = new Array();

	if (!ConfigObjectUtility::CreateObject(Comment::TypeInstance, fullName, config, errors)) {
		ObjectLock olock(errors);
		BOOST_FOREACH(const String& error, errors) {
			Log(LogCritical, "Comment", error);
		}
Exemple #7
0
Object::Ptr Dictionary::GetPrototype(void)
{
	static Dictionary::Ptr prototype;

	if (!prototype) {
		prototype = new Dictionary();
		prototype->Set("len", new Function(WrapFunction(DictionaryLen), true));
		prototype->Set("set", new Function(WrapFunction(DictionarySet)));
		prototype->Set("remove", new Function(WrapFunction(DictionaryRemove)));
		prototype->Set("contains", new Function(WrapFunction(DictionaryContains), true));
		prototype->Set("clone", new Function(WrapFunction(DictionaryClone), true));
	}

	return prototype;
}
Exemple #8
0
Dictionary::Ptr ApiActions::RescheduleCheck(const ConfigObject::Ptr& object,
    const Dictionary::Ptr& params)
{
	Checkable::Ptr checkable = static_pointer_cast<Checkable>(object);

	if (!checkable)
		return ApiActions::CreateResult(404, "Cannot reschedule check for non-existent object.");

	if (Convert::ToBool(HttpUtility::GetLastParameter(params, "force")))
		checkable->SetForceNextCheck(true);

	double nextCheck;
	if (params->Contains("next_check"))
		nextCheck = HttpUtility::GetLastParameter(params, "next_check");
	else
		nextCheck = Utility::GetTime();

	checkable->SetNextCheck(nextCheck);

	return ApiActions::CreateResult(200, "Successfully rescheduled check for object '" + checkable->GetName() + "'.");
}
std::pair<double, double> ScheduledDowntime::FindNextSegment()
{
	time_t refts = Utility::GetTime();
	tm reference = Utility::LocalTime(refts);

	Log(LogDebug, "ScheduledDowntime")
		<< "Finding next scheduled downtime segment for time " << refts;

	Dictionary::Ptr ranges = GetRanges();

	if (!ranges)
		return std::make_pair(0, 0);

	Array::Ptr segments = new Array();

	Dictionary::Ptr bestSegment;
	double bestBegin;
	double now = Utility::GetTime();

	ObjectLock olock(ranges);
	for (const Dictionary::Pair& kv : ranges) {
		Log(LogDebug, "ScheduledDowntime")
			<< "Evaluating segment: " << kv.first << ": " << kv.second << " at ";

		Dictionary::Ptr segment = LegacyTimePeriod::FindNextSegment(kv.first, kv.second, &reference);

		if (!segment)
			continue;

		Log(LogDebug, "ScheduledDowntime")
			<< "Considering segment: " << Utility::FormatDateTime("%c", segment->Get("begin")) << " -> " << Utility::FormatDateTime("%c", segment->Get("end"));

		double begin = segment->Get("begin");

		if (begin < now)
			continue;

		if (!bestSegment || begin < bestBegin) {
			bestSegment = segment;
			bestBegin = begin;
		}
	}

	if (bestSegment)
		return std::make_pair(bestSegment->Get("begin"), bestSegment->Get("end"));
	else
		return std::make_pair(0, 0);
}
bool ApiListener::UpdateConfigDir(const Dictionary::Ptr& oldConfig, const Dictionary::Ptr& newConfig, const String& configDir)
{
	bool configChange = false;

	if (oldConfig->Contains(".timestamp") && newConfig->Contains(".timestamp")) {
		double oldTS = Convert::ToDouble(oldConfig->Get(".timestamp"));
		double newTS = Convert::ToDouble(newConfig->Get(".timestamp"));

		/* skip update if our config is newer */
		if (oldTS <= newTS)
			return false;
	}

	BOOST_FOREACH(const Dictionary::Pair& kv, newConfig) {
		if (oldConfig->Get(kv.first) != kv.second) {
			configChange = true;

			String path = configDir + "/" + kv.first;
			Log(LogInformation, "ApiListener")
			    << "Updating configuration file: " << path;

			//pass the directory and generate a dir tree, if not existing already
			Utility::MkDirP(Utility::DirName(path), 0755);
			std::ofstream fp(path.CStr(), std::ofstream::out | std::ostream::trunc);
			fp << kv.second;
			fp.close();
		}
	}

	BOOST_FOREACH(const Dictionary::Pair& kv, oldConfig) {
		if (!newConfig->Contains(kv.first)) {
			configChange = true;

			String path = configDir + "/" + kv.first;
			(void) unlink(path.CStr());
		}
	}

	String tsPath = configDir + "/.timestamp";
	if (!Utility::PathExists(tsPath)) {
		std::ofstream fp(tsPath.CStr(), std::ofstream::out | std::ostream::trunc);
		fp << Utility::GetTime();
		fp.close();
	}

	return configChange;
}
void InfluxdbWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata)
{
	DictionaryData nodes;

	for (const InfluxdbWriter::Ptr& influxdbwriter : ConfigType::GetObjectsByType<InfluxdbWriter>()) {
		size_t workQueueItems = influxdbwriter->m_WorkQueue.GetLength();
		double workQueueItemRate = influxdbwriter->m_WorkQueue.GetTaskCount(60) / 60.0;
		size_t dataBufferItems = influxdbwriter->m_DataBuffer.size();

		nodes.emplace_back(influxdbwriter->GetName(), new Dictionary({
			{ "work_queue_items", workQueueItems },
			{ "work_queue_item_rate", workQueueItemRate },
			{ "data_buffer_items", dataBufferItems }
		}));

		perfdata->Add(new PerfdataValue("influxdbwriter_" + influxdbwriter->GetName() + "_work_queue_items", workQueueItems));
		perfdata->Add(new PerfdataValue("influxdbwriter_" + influxdbwriter->GetName() + "_work_queue_item_rate", workQueueItemRate));
		perfdata->Add(new PerfdataValue("influxdbwriter_" + influxdbwriter->GetName() + "_data_queue_items", dataBufferItems));
	}

	status->Set("influxdbwriter", new Dictionary(std::move(nodes)));
}
Exemple #12
0
void ClusterEvents::ForceNextNotificationChangedHandler(const Checkable::Ptr& checkable, const MessageOrigin::Ptr& origin)
{
	ApiListener::Ptr listener = ApiListener::GetInstance();

	if (!listener)
		return;

	Host::Ptr host;
	Service::Ptr service;
	tie(host, service) = GetHostService(checkable);

	Dictionary::Ptr params = new Dictionary();
	params->Set("host", host->GetName());
	if (service)
		params->Set("service", service->GetShortName());
	params->Set("forced", checkable->GetForceNextNotification());

	Dictionary::Ptr message = new Dictionary();
	message->Set("jsonrpc", "2.0");
	message->Set("method", "event::SetForceNextNotification");
	message->Set("params", params);

	listener->RelayMessage(origin, checkable, message, true);
}
void IdoPgsqlConnection::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata)
{
	Dictionary::Ptr nodes = new Dictionary();

	for (const IdoPgsqlConnection::Ptr& idopgsqlconnection : ConfigType::GetObjectsByType<IdoPgsqlConnection>()) {
		size_t items = idopgsqlconnection->m_QueryQueue.GetLength();

		Dictionary::Ptr stats = new Dictionary();
		stats->Set("version", idopgsqlconnection->GetSchemaVersion());
		stats->Set("connected", idopgsqlconnection->GetConnected());
		stats->Set("instance_name", idopgsqlconnection->GetInstanceName());
		stats->Set("query_queue_items", items);

		nodes->Set(idopgsqlconnection->GetName(), stats);

		perfdata->Add(new PerfdataValue("idopgsqlconnection_" + idopgsqlconnection->GetName() + "_queries_rate", idopgsqlconnection->GetQueryCount(60) / 60.0));
		perfdata->Add(new PerfdataValue("idopgsqlconnection_" + idopgsqlconnection->GetName() + "_queries_1min", idopgsqlconnection->GetQueryCount(60)));
		perfdata->Add(new PerfdataValue("idopgsqlconnection_" + idopgsqlconnection->GetName() + "_queries_5mins", idopgsqlconnection->GetQueryCount(5 * 60)));
		perfdata->Add(new PerfdataValue("idopgsqlconnection_" + idopgsqlconnection->GetName() + "_queries_15mins", idopgsqlconnection->GetQueryCount(15 * 60)));
		perfdata->Add(new PerfdataValue("idopgsqlconnection_" + idopgsqlconnection->GetName() + "_query_queue_items", items));
	}

	status->Set("idopgsqlconnection", nodes);
}
Exemple #14
0
void ApiListener::SyncSendMessage(const Endpoint::Ptr& endpoint, const Dictionary::Ptr& message)
{
	ObjectLock olock(endpoint);

	if (!endpoint->GetSyncing()) {
		Log(LogNotice, "ApiListener")
		    << "Sending message '" << message->Get("method") << "' to '" << endpoint->GetName() << "'";

		double maxTs = 0;

		for (const JsonRpcConnection::Ptr& client : endpoint->GetClients()) {
			if (client->GetTimestamp() > maxTs)
				maxTs = client->GetTimestamp();
		}

		for (const JsonRpcConnection::Ptr& client : endpoint->GetClients()) {
			if (client->GetTimestamp() != maxTs)
				continue;

			client->SendMessage(message);
		}
	}
}
Exemple #15
0
void ApiClient::AutocompleteScriptHttpCompletionCallback(HttpRequest& request,
	HttpResponse& response, const AutocompleteScriptCompletionCallback& callback)
{
	Dictionary::Ptr result;

	String body;
	char buffer[1024];
	size_t count;

	while ((count = response.ReadBody(buffer, sizeof(buffer))) > 0)
		body += String(buffer, buffer + count);

	try {
		if (response.StatusCode < 200 || response.StatusCode > 299) {
			std::string message = "HTTP request failed; Code: " + Convert::ToString(response.StatusCode) + "; Body: " + body;

			BOOST_THROW_EXCEPTION(ScriptError(message));
		}

		result = JsonDecode(body);

		Array::Ptr results = result->Get("results");
		Array::Ptr suggestions;
		String errorMessage = "Unexpected result from API.";

		if (results && results->GetLength() > 0) {
			Dictionary::Ptr resultInfo = results->Get(0);
			errorMessage = resultInfo->Get("status");

			if (resultInfo->Get("code") >= 200 && resultInfo->Get("code") <= 299)
				suggestions = resultInfo->Get("suggestions");
			else
				BOOST_THROW_EXCEPTION(ScriptError(errorMessage));
		}

		callback(boost::exception_ptr(), suggestions);
	} catch (const std::exception&) {
		callback(boost::current_exception(), nullptr);
	}
}
void ObjectListUtility::PrintProperties(std::ostream& fp, const Dictionary::Ptr& props, const Dictionary::Ptr& debug_hints, int indent)
{
	/* get debug hint props */
	Dictionary::Ptr debug_hint_props;
	if (debug_hints)
		debug_hint_props = debug_hints->Get("properties");

	int offset = 2;

	ObjectLock olock(props);
	for (const Dictionary::Pair& kv : props)
	{
		String key = kv.first;
		Value val = kv.second;

		/* key & value */
		fp << std::setw(indent) << " " << "* " << ConsoleColorTag(Console_ForegroundGreen) << key << ConsoleColorTag(Console_Normal);

		/* extract debug hints for key */
		Dictionary::Ptr debug_hints_fwd;
		if (debug_hint_props)
			debug_hints_fwd = debug_hint_props->Get(key);

		/* print dicts recursively */
		if (val.IsObjectType<Dictionary>()) {
			fp << "\n";
			PrintHints(fp, debug_hints_fwd, indent + offset);
			PrintProperties(fp, val, debug_hints_fwd, indent + offset);
		} else {
			fp << " = ";
			PrintValue(fp, val);
			fp << "\n";
			PrintHints(fp, debug_hints_fwd, indent + offset);
		}
	}
}
bool ObjectListUtility::PrintObject(std::ostream& fp, bool& first, const String& message, std::map<String, int>& type_count, const String& name_filter, const String& type_filter)
{
	Dictionary::Ptr object = JsonDecode(message);

	Dictionary::Ptr properties = object->Get("properties");

	String internal_name = properties->Get("__name");
	String name = object->Get("name");
	String type = object->Get("type");

	if (!name_filter.IsEmpty() && !Utility::Match(name_filter, name) && !Utility::Match(name_filter, internal_name))
		return false;
	if (!type_filter.IsEmpty() && !Utility::Match(type_filter, type))
		return false;

	if (first)
		first = false;
	else
		fp << "\n";

	Dictionary::Ptr debug_hints = object->Get("debug_hints");

	fp << "Object '" << ConsoleColorTag(Console_ForegroundBlue | Console_Bold) << internal_name << ConsoleColorTag(Console_Normal) << "'";
	fp << " of type '" << ConsoleColorTag(Console_ForegroundMagenta | Console_Bold) << type << ConsoleColorTag(Console_Normal) << "':\n";

	Array::Ptr di = object->Get("debug_info");

	if (di) {
		fp << ConsoleColorTag(Console_ForegroundCyan) << "  % declared in '" << di->Get(0) << "', lines "
			<< di->Get(1) << ":" << di->Get(2) << "-" << di->Get(3) << ":" << di->Get(4) << ConsoleColorTag(Console_Normal) << "\n";
	}

	PrintProperties(fp, properties, debug_hints, 2);

	type_count[type]++;
	return true;
}
bool TroubleshootCommand::CheckFeatures(InfoLog& log)
{
	Dictionary::Ptr features = new Dictionary;
	std::vector<String> disabled_features;
	std::vector<String> enabled_features;

	if (!FeatureUtility::GetFeatures(disabled_features, true) ||
		!FeatureUtility::GetFeatures(enabled_features, false)) {
		InfoLogLine(log, 0, LogCritical)
			<< "Failed to collect enabled and/or disabled features. Check\n"
			<< FeatureUtility::GetFeaturesAvailablePath() << '\n'
			<< FeatureUtility::GetFeaturesEnabledPath() << '\n';
		return false;
	}

	for (const String& feature : disabled_features)
		features->Set(feature, false);
	for (const String& feature : enabled_features)
		features->Set(feature, true);

	InfoLogLine(log)
		<< "Enabled features:\n";
	InfoLogLine(log, Console_ForegroundGreen)
		<< '\t' << boost::algorithm::join(enabled_features, " ") << '\n';
	InfoLogLine(log)
		<< "Disabled features:\n";
	InfoLogLine(log, Console_ForegroundRed)
		<< '\t' << boost::algorithm::join(disabled_features, " ") << '\n';

	if (!features->Get("checker").ToBool())
		InfoLogLine(log, 0, LogWarning)
			<< "checker is disabled, no checks can be run from this instance\n";
	if (!features->Get("mainlog").ToBool())
		InfoLogLine(log, 0, LogWarning)
			<< "mainlog is disabled, please activate it and rerun icinga2\n";
	if (!features->Get("debuglog").ToBool())
		InfoLogLine(log, 0, LogWarning)
			<< "debuglog is disabled, please activate it and rerun icinga2\n";

	return true;
}
void CheckerComponent::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata)
{
	Dictionary::Ptr nodes = new Dictionary();

	for (const CheckerComponent::Ptr& checker : ConfigType::GetObjectsByType<CheckerComponent>()) {
		unsigned long idle = checker->GetIdleCheckables();
		unsigned long pending = checker->GetPendingCheckables();

		Dictionary::Ptr stats = new Dictionary();
		stats->Set("idle", idle);
		stats->Set("pending", pending);

		nodes->Set(checker->GetName(), stats);

		String perfdata_prefix = "checkercomponent_" + checker->GetName() + "_";
		perfdata->Add(new PerfdataValue(perfdata_prefix + "idle", Convert::ToDouble(idle)));
		perfdata->Add(new PerfdataValue(perfdata_prefix + "pending", Convert::ToDouble(pending)));
	}

	status->Set("checkercomponent", nodes);
}
Exemple #20
0
void InfluxdbWriter::CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr)
{
	CONTEXT("Processing check result for '" + checkable->GetName() + "'");

	if (!IcingaApplication::GetInstance()->GetEnablePerfdata() || !checkable->GetEnablePerfdata())
		return;

	Host::Ptr host;
	Service::Ptr service;
	boost::tie(host, service) = GetHostService(checkable);

	MacroProcessor::ResolverList resolvers;
	if (service)
		resolvers.push_back(std::make_pair("service", service));
	resolvers.push_back(std::make_pair("host", host));
	resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance()));

	String prefix;

	double ts = cr->GetExecutionEnd();

	// Clone the template and perform an in-place macro expansion of measurement and tag values
	Dictionary::Ptr tmpl_clean = service ? GetServiceTemplate() : GetHostTemplate();
	Dictionary::Ptr tmpl = static_pointer_cast<Dictionary>(tmpl_clean->Clone());
	tmpl->Set("measurement", MacroProcessor::ResolveMacros(tmpl->Get("measurement"), resolvers, cr));

	Dictionary::Ptr tags = tmpl->Get("tags");
	if (tags) {
		ObjectLock olock(tags);
		for (const Dictionary::Pair& pair : tags) {
			// Prevent missing macros from warning; will return an empty value
			// which will be filtered out in SendMetric()
			String missing_macro;
			tags->Set(pair.first,  MacroProcessor::ResolveMacros(pair.second, resolvers, cr, &missing_macro));
		}
	}

	SendPerfdata(tmpl, checkable, cr, ts);
}
Exemple #21
0
Value RequestCertificateHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params)
{
	if (!params)
		return Empty;

	Dictionary::Ptr result = new Dictionary();

	if (!origin->FromClient->IsAuthenticated()) {
		ApiListener::Ptr listener = ApiListener::GetInstance();
		String salt = listener->GetTicketSalt();

		if (salt.IsEmpty()) {
			result->Set("error", "Ticket salt is not configured.");
			return result;
		}

		String ticket = params->Get("ticket");
		String realTicket = PBKDF2_SHA1(origin->FromClient->GetIdentity(), salt, 50000);

		if (ticket != realTicket) {
			result->Set("error", "Invalid ticket.");
			return result;
		}
	}

	boost::shared_ptr<X509> cert = origin->FromClient->GetStream()->GetPeerCertificate();

	EVP_PKEY *pubkey = X509_get_pubkey(cert.get());
	X509_NAME *subject = X509_get_subject_name(cert.get());

	boost::shared_ptr<X509> newcert = CreateCertIcingaCA(pubkey, subject);
	result->Set("cert", CertificateToString(newcert));

	String cacertfile = GetIcingaCADir() + "/ca.crt";
	boost::shared_ptr<X509> cacert = GetX509Certificate(cacertfile);
	result->Set("ca", CertificateToString(cacert));

	return result;
}
Exemple #22
0
	BOOST_FOREACH(const Endpoint::Ptr& endpoint, ConfigType::GetObjectsByType<Endpoint>()) {
		if (!endpoint->IsConnected())
			continue;

		double ts = endpoint->GetRemoteLogPosition();

		if (ts == 0)
			continue;

		Dictionary::Ptr lparams = new Dictionary();
		lparams->Set("log_position", ts);

		Dictionary::Ptr lmessage = new Dictionary();
		lmessage->Set("jsonrpc", "2.0");
		lmessage->Set("method", "log::SetLogPosition");
		lmessage->Set("params", lparams);

		BOOST_FOREACH(const JsonRpcConnection::Ptr& client, endpoint->GetClients())
			client->SendMessage(lmessage);

		Log(LogNotice, "ApiListener")
		    << "Setting log position for identity '" << endpoint->GetName() << "': "
		    << Utility::FormatDateTime("%Y/%m/%d %H:%M:%S", ts);
	}
bool ActionsHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
{
	if (request.RequestUrl->GetPath().size() != 3)
		return false;

	if (request.RequestMethod != "POST")
		return false;

	String actionName = request.RequestUrl->GetPath()[2];

	ApiAction::Ptr action = ApiAction::GetByName(actionName);

	if (!action) {
		HttpUtility::SendJsonError(response, 404, "Action '" + actionName + "' does not exist.");
		return true;
	}

	QueryDescription qd;

	Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);

	const std::vector<String>& types = action->GetTypes();
	std::vector<Value> objs;

	String permission = "actions/" + actionName;

	if (!types.empty()) {
		qd.Types = std::set<String>(types.begin(), types.end());
		qd.Permission = permission;

		try {
			objs = FilterUtility::GetFilterTargets(qd, params, user);
		} catch (const std::exception& ex) {
			HttpUtility::SendJsonError(response, 400,
			    "Type/Filter was required but not provided or was invalid.",
			    HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : "");
			return true;
		}
	} else {
		FilterUtility::CheckPermission(user, permission);
		objs.push_back(ConfigObject::Ptr());
	}

	Array::Ptr results = new Array();

	Log(LogNotice, "ApiActionHandler")
	    << "Running action " << actionName;

	BOOST_FOREACH(const ConfigObject::Ptr& obj, objs) {
		try {
			results->Add(action->Invoke(obj, params));
		} catch (const std::exception& ex) {
			Dictionary::Ptr fail = new Dictionary();
			fail->Set("code", 500);
			fail->Set("status", "Action execution failed: '" + DiagnosticInformation(ex, false) + "'.");
			if (HttpUtility::GetLastParameter(params, "verboseErrors"))
				fail->Set("diagnostic information", DiagnosticInformation(ex));
			results->Add(fail);
		}
	}

	Dictionary::Ptr result = new Dictionary();
	result->Set("results", results);

	response.SetStatus(200, "OK");
	HttpUtility::SendJsonBody(response, result);

	return true;
}
Exemple #24
0
/**
 * Processes a new client connection.
 *
 * @param client The new client.
 */
void ApiListener::NewClientHandlerInternal(const Socket::Ptr& client, const String& hostname, ConnectionRole role)
{
	CONTEXT("Handling new API client connection");

	TlsStream::Ptr tlsStream;

	{
		ObjectLock olock(this);
		try {
			tlsStream = new TlsStream(client, hostname, role, m_SSLContext);
		} catch (const std::exception&) {
			Log(LogCritical, "ApiListener", "Cannot create TLS stream from client connection.");
			return;
		}
	}

	try {
		tlsStream->Handshake();
	} catch (const std::exception& ex) {
		Log(LogCritical, "ApiListener", "Client TLS handshake failed");
		return;
	}

	boost::shared_ptr<X509> cert = tlsStream->GetPeerCertificate();
	String identity;
	Endpoint::Ptr endpoint;
	bool verify_ok = false;

	if (cert) {
		try {
			identity = GetCertificateCN(cert);
		} catch (const std::exception&) {
			Log(LogCritical, "ApiListener")
			    << "Cannot get certificate common name from cert path: '" << GetCertPath() << "'.";
			return;
		}

		verify_ok = tlsStream->IsVerifyOK();

		Log(LogInformation, "ApiListener")
		    << "New client connection for identity '" << identity << "'" << (verify_ok ? "" : " (unauthenticated)");


		if (verify_ok)
			endpoint = Endpoint::GetByName(identity);
	} else {
		Log(LogInformation, "ApiListener")
		    << "New client connection (no client certificate)";
	}

	bool need_sync = false;

	if (endpoint)
		need_sync = !endpoint->IsConnected();

	ClientType ctype;

	if (role == RoleClient) {
		Dictionary::Ptr message = new Dictionary();
		message->Set("jsonrpc", "2.0");
		message->Set("method", "icinga::Hello");
		message->Set("params", new Dictionary());
		JsonRpc::SendMessage(tlsStream, message);
		ctype = ClientJsonRpc;
	} else {
		tlsStream->WaitForData(5);

		if (!tlsStream->IsDataAvailable()) {
			Log(LogWarning, "ApiListener", "No data received on new API connection.");
			return;
		}

		char firstByte;
		tlsStream->Peek(&firstByte, 1, false);

		if (firstByte >= '0' && firstByte <= '9')
			ctype = ClientJsonRpc;
		else
			ctype = ClientHttp;
	}

	if (ctype == ClientJsonRpc) {
		Log(LogNotice, "ApiListener", "New JSON-RPC client");

		JsonRpcConnection::Ptr aclient = new JsonRpcConnection(identity, verify_ok, tlsStream, role);
		aclient->Start();

		if (endpoint) {
			endpoint->AddClient(aclient);

			if (need_sync) {
				{
					ObjectLock olock(endpoint);

					endpoint->SetSyncing(true);
				}

				Log(LogInformation, "ApiListener")
				    << "Sending updates for endpoint '" << endpoint->GetName() << "'.";

				/* sync zone file config */
				SendConfigUpdate(aclient);
				/* sync runtime config */
				SendRuntimeConfigObjects(aclient);

				Log(LogInformation, "ApiListener")
				    << "Finished sending updates for endpoint '" << endpoint->GetName() << "'.";

				ReplayLog(aclient);
			}
		} else
			AddAnonymousClient(aclient);
	} else {
		Log(LogNotice, "ApiListener", "New HTTP client");

		HttpServerConnection::Ptr aclient = new HttpServerConnection(identity, verify_ok, tlsStream);
		aclient->Start();
		AddHttpClient(aclient);
	}
}
Exemple #25
0
static Dictionary::Ptr DictionaryClone(void)
{
	ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
	Dictionary::Ptr self = static_cast<Dictionary::Ptr>(vframe->Self);
	return self->ShallowClone();
}
Exemple #26
0
static bool DictionaryContains(const String& key)
{
	ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
	Dictionary::Ptr self = static_cast<Dictionary::Ptr>(vframe->Self);
	return self->Contains(key);
}
Exemple #27
0
static void DictionarySet(const String& key, const Value& value)
{
	ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
	Dictionary::Ptr self = static_cast<Dictionary::Ptr>(vframe->Self);
	self->Set(key, value);
}
Exemple #28
0
void Checkable::ExecuteCheck()
{
    CONTEXT("Executing check for object '" + GetName() + "'");

    ASSERT(!OwnsLock());

    UpdateNextCheck();

    bool reachable = IsReachable();

    {
        ObjectLock olock(this);

        /* don't run another check if there is one pending */
        if (m_CheckRunning)
            return;

        m_CheckRunning = true;

        SetLastStateRaw(GetStateRaw());
        SetLastStateType(GetLastStateType());
        SetLastReachable(reachable);
    }

    /* keep track of scheduling info in case the check type doesn't provide its own information */
    double scheduled_start = GetNextCheck();
    double before_check = Utility::GetTime();

    CheckResult::Ptr cr = new CheckResult();

    cr->SetScheduleStart(scheduled_start);
    cr->SetExecutionStart(before_check);

    Endpoint::Ptr endpoint = GetCommandEndpoint();
    bool local = !endpoint || endpoint == Endpoint::GetLocalEndpoint();

    if (local) {
        GetCheckCommand()->Execute(this, cr, NULL, false);
    } else {
        Dictionary::Ptr macros = new Dictionary();
        GetCheckCommand()->Execute(this, cr, macros, false);

        if (endpoint->GetConnected()) {
            /* perform check on remote endpoint */
            Dictionary::Ptr message = new Dictionary();
            message->Set("jsonrpc", "2.0");
            message->Set("method", "event::ExecuteCommand");

            Host::Ptr host;
            Service::Ptr service;
            tie(host, service) = GetHostService(this);

            Dictionary::Ptr params = new Dictionary();
            message->Set("params", params);
            params->Set("command_type", "check_command");
            params->Set("command", GetCheckCommand()->GetName());
            params->Set("host", host->GetName());

            if (service)
                params->Set("service", service->GetShortName());

            params->Set("macros", macros);

            ApiListener::Ptr listener = ApiListener::GetInstance();

            if (listener)
                listener->SyncSendMessage(endpoint, message);

        } else if (Application::GetInstance()->GetStartTime() < Utility::GetTime() - 30) {
            /* fail to perform check on unconnected endpoint */
            cr->SetState(ServiceUnknown);

            cr->SetOutput("Remote Icinga instance '" + endpoint->GetName() +
                          "' " + "is not connected to '" + Endpoint::GetLocalEndpoint()->GetName() + "'");

            ProcessCheckResult(cr);
        }

        {
            ObjectLock olock(this);
            m_CheckRunning = false;
        }
    }
}
Exemple #29
0
int PkiUtility::RequestCertificate(const String& host, const String& port, const String& keyfile,
    const String& certfile, const String& cafile, const boost::shared_ptr<X509>& trustedCert, const String& ticket)
{
	TcpSocket::Ptr client = new TcpSocket();

	try {
		client->Connect(host, port);
	} catch (const std::exception& ex) {
		Log(LogCritical, "cli")
		    << "Cannot connect to host '" << host << "' on port '" << port << "'";
		Log(LogDebug, "cli")
		    << "Cannot connect to host '" << host << "' on port '" << port << "':\n" << DiagnosticInformation(ex);
		return 1;
	}

	boost::shared_ptr<SSL_CTX> sslContext;

	try {
		sslContext = MakeSSLContext(certfile, keyfile);
	} catch (const std::exception& ex) {
		Log(LogCritical, "cli")
		    << "Cannot make SSL context for cert path: '" << certfile << "' key path: '" << keyfile << "' ca path: '" << cafile << "'.";
		Log(LogDebug, "cli")
		    << "Cannot make SSL context for cert path: '" << certfile << "' key path: '" << keyfile << "' ca path: '" << cafile << "':\n"  << DiagnosticInformation(ex);
		return 1;
	}

	TlsStream::Ptr stream = new TlsStream(client, host, RoleClient, sslContext);

	try {
		stream->Handshake();
	} catch (const std::exception&) {
		Log(LogCritical, "cli", "Client TLS handshake failed.");
		return 1;
	}

	boost::shared_ptr<X509> peerCert = stream->GetPeerCertificate();

	if (X509_cmp(peerCert.get(), trustedCert.get())) {
		Log(LogCritical, "cli", "Peer certificate does not match trusted certificate.");
		return 1;
	}

	Dictionary::Ptr request = new Dictionary();

	String msgid = Utility::NewUniqueID();

	request->Set("jsonrpc", "2.0");
	request->Set("id", msgid);
	request->Set("method", "pki::RequestCertificate");

	Dictionary::Ptr params = new Dictionary();
	params->Set("ticket", String(ticket));

	request->Set("params", params);

	JsonRpc::SendMessage(stream, request);

	String jsonString;
	Dictionary::Ptr response;
	StreamReadContext src;

	for (;;) {
		StreamReadStatus srs = JsonRpc::ReadMessage(stream, &jsonString, src);

		if (srs == StatusEof)
			break;

		if (srs != StatusNewItem)
			continue;

		response = JsonRpc::DecodeMessage(jsonString);

		if (response && response->Contains("error")) {
			Log(LogCritical, "cli", "Could not fetch valid response. Please check the master log (notice or debug).");
#ifdef I2_DEBUG
			/* we shouldn't expose master errors to the user in production environments */
			Log(LogCritical, "cli", response->Get("error"));
#endif /* I2_DEBUG */
			return 1;
		}

		if (response && (response->Get("id") != msgid))
			continue;

		break;
	}

	if (!response) {
		Log(LogCritical, "cli", "Could not fetch valid response. Please check the master log.");
		return 1;
	}

	Dictionary::Ptr result = response->Get("result");

	if (result->Contains("error")) {
		Log(LogCritical, "cli", result->Get("error"));
		return 1;
	}

	std::ofstream fpcert;
	fpcert.open(certfile.CStr());
	fpcert << result->Get("cert");
	fpcert.close();

	if (fpcert.fail()) {
		Log(LogCritical, "cli")
		    << "Could not write certificate to file '" << certfile << "'.";
		return 1;
	}

	Log(LogInformation, "cli")
	    << "Writing signed certificate to file '" << certfile << "'.";

	std::ofstream fpca;
	fpca.open(cafile.CStr());
	fpca << result->Get("ca");
	fpca.close();

	if (fpca.fail()) {
		Log(LogCritical, "cli")
		    << "Could not open CA certificate file '" << cafile << "' for writing.";
		return 1;
	}

	Log(LogInformation, "cli")
	    << "Writing CA certificate to file '" << cafile << "'.";

	return 0;
}
Exemple #30
0
static void DictionaryRemove(const String& key)
{
	ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
	Dictionary::Ptr self = static_cast<Dictionary::Ptr>(vframe->Self);
	self->Remove(key);
}