[pkg-nagios-changes] [Git][nagios-team/pkg-icinga2][master] 4 commits: New upstream version 2.12.2

Bas Couwenberg gitlab at salsa.debian.org
Thu Nov 26 05:00:48 GMT 2020



Bas Couwenberg pushed to branch master at Debian Nagios Maintainer Group / pkg-icinga2


Commits:
f3aa2f9d by Bas Couwenberg at 2020-11-26T05:30:54+01:00
New upstream version 2.12.2
- - - - -
1367bea8 by Bas Couwenberg at 2020-11-26T05:31:22+01:00
Update upstream source from tag 'upstream/2.12.2'

Update to upstream version '2.12.2'
with Debian dir ba52329eb85a526e903129ee66d3bd67115dd5a3
- - - - -
1b3d6223 by Bas Couwenberg at 2020-11-26T05:31:47+01:00
New upstream release.

- - - - -
3c21532f by Bas Couwenberg at 2020-11-26T05:33:02+01:00
Set distribution to unstable.

- - - - -


10 changed files:

- .github/workflows/packages.yml
- AUTHORS
- CHANGELOG.md
- VERSION
- debian/changelog
- lib/remote/apilistener-configsync.cpp
- lib/remote/apilistener-filesync.cpp
- lib/remote/apilistener.cpp
- lib/remote/httpserverconnection.cpp
- lib/remote/jsonrpcconnection.cpp


Changes:

=====================================
.github/workflows/packages.yml
=====================================
@@ -21,6 +21,9 @@ jobs:
           - name: debian
             codename: stretch
             has32bit: true
+          - name: ubuntu
+            codename: groovy
+            has32bit: false
           - name: ubuntu
             codename: focal
             has32bit: false


=====================================
AUTHORS
=====================================
@@ -75,7 +75,7 @@ Elias Ohm <eohm at novomind.com>
 Eric Lippmann <eric.lippmann at icinga.com>
 Evgeni Golov <evgeni at golov.de>
 Ewoud Kohl van Wijngaarden <ewoud at kohlvanwijngaarden.nl>
-Fabian Röhl <FRoehl at freicon.de>
+Fabian Röhl <mail at fabian-roehl.de>
 fbachmann <bachmann.f at gmail.com>
 Federico Cuello <federico.cuello at sociomantic.com>
 Federico Pires <federico.pires at upsight.com>
@@ -130,7 +130,7 @@ krishna <gskrishna44 at gmail.com>
 Lars Engels <lars.engels at 0x20.net>
 Lars Krüger <krueger-lars at web.de>
 Leah Oswald <mail at leahoswald.de>
-Lee Clemens <java at leeclemens.net>
+Lee Clemens <sftw at leeclemens.net>
 Lee Garrett <lgarrett at rocketjump.eu>
 Lennart Betz <lennart.betz at icinga.com>
 Leon Stringer <leon at priorsvle.com>


=====================================
CHANGELOG.md
=====================================
@@ -7,6 +7,23 @@ documentation before upgrading to a new release.
 
 Released closed milestones can be found on [GitHub](https://github.com/Icinga/icinga2/milestones?state=closed).
 
+## 2.12.2 (2020-12-01)
+
+Version 2.12.2 fixes several issues to improve the reliability of the cluster functionality.
+
+### Bugfixes
+
+* Fix a connection leak with misconfigured agents #8483
+* Properly sync changes of config objects in global zones done via the API #8474 #8470
+* Prevent other clients from being disconnected when replaying the cluster log takes very long #8496
+* Avoid duplicate connections between endpoints #8465
+* Ignore incoming config object updates for unknown zones #8461
+* Check timestamps before removing files in config sync #8495
+
+### Enhancements
+
+* Include HTTP status codes in log #8467
+
 ## 2.12.1 (2020-10-15)
 
 Version 2.12.1 fixes several crashes, deadlocks and excessive check latencies.


=====================================
VERSION
=====================================
@@ -1,2 +1,2 @@
-Version: 2.12.1
+Version: 2.12.2
 Revision: 1


=====================================
debian/changelog
=====================================
@@ -1,3 +1,10 @@
+icinga2 (2.12.2-1) unstable; urgency=medium
+
+  * Team upload.
+  * New upstream release.
+
+ -- Bas Couwenberg <sebastic at debian.org>  Thu, 26 Nov 2020 05:32:44 +0100
+
 icinga2 (2.12.1-2) unstable; urgency=medium
 
   * Team upload.


=====================================
lib/remote/apilistener-configsync.cpp
=====================================
@@ -72,6 +72,16 @@ Value ApiListener::ConfigUpdateObjectAPIHandler(const MessageOrigin::Ptr& origin
 		return Empty;
 	}
 
+	String objZone = params->Get("zone");
+
+	if (!Zone::GetByName(objZone)) {
+		Log(LogNotice, "ApiListener")
+			<< "Discarding 'config update object' message"
+			<< " from '" << identity << "' (endpoint: '" << endpoint->GetName() << "', zone: '" << endpointZone->GetName() << "')"
+			<< " for object '" << objName << "' of type '" << objType << "'. Objects zone '" << objZone << "' isn't known locally.";
+		return Empty;
+	}
+
 	/* ignore messages if the endpoint does not accept config */
 	if (!listener->GetAcceptConfig()) {
 		Log(LogWarning, "ApiListener")
@@ -315,6 +325,7 @@ void ApiListener::UpdateConfigObject(const ConfigObject::Ptr& object, const Mess
 	params->Set("name", object->GetName());
 	params->Set("type", object->GetReflectionType()->GetName());
 	params->Set("version", object->GetVersion());
+	params->Set("zone", object->GetZoneName());
 
 	if (object->GetPackage() == "_api") {
 		String file;
@@ -423,7 +434,7 @@ void ApiListener::DeleteConfigObject(const ConfigObject::Ptr& object, const Mess
 		if (!target)
 			target = Zone::GetLocalZone();
 
-		RelayMessage(origin, target, message, false);
+		RelayMessage(origin, target, message, true);
 	}
 }
 


=====================================
lib/remote/apilistener-filesync.cpp
=====================================
@@ -421,6 +421,12 @@ void ApiListener::HandleConfigUpdate(const MessageOrigin::Ptr& origin, const Dic
 		Dictionary::Ptr productionConfig = MergeConfigUpdate(productionConfigInfo);
 		Dictionary::Ptr newConfig = MergeConfigUpdate(newConfigInfo);
 
+		bool timestampChanged = false;
+
+		if (CompareTimestampsConfigChange(productionConfig, newConfig, stageConfigZoneDir)) {
+			timestampChanged = true;
+		}
+
 		/* If we have received 'checksums' via cluster message, go for it.
 		 * Otherwise do the old timestamp dance for versions < 2.11.
 		 */
@@ -429,7 +435,7 @@ void ApiListener::HandleConfigUpdate(const MessageOrigin::Ptr& origin, const Dic
 				<< "Received configuration for zone '" << zoneName << "' from endpoint '"
 				<< fromEndpointName << "'. Comparing the timestamp and checksums.";
 
-			if (CompareTimestampsConfigChange(productionConfig, newConfig, stageConfigZoneDir)) {
+			if (timestampChanged) {
 
 				if (CheckConfigChange(productionConfigInfo, newConfigInfo))
 					configChange = true;
@@ -446,7 +452,7 @@ void ApiListener::HandleConfigUpdate(const MessageOrigin::Ptr& origin, const Dic
 				<< "Received configuration update without checksums from parent endpoint "
 				<< fromEndpointName << ". This behaviour is deprecated. Please upgrade the parent endpoint to 2.11+";
 
-			if (CompareTimestampsConfigChange(productionConfig, newConfig, stageConfigZoneDir)) {
+			if (timestampChanged) {
 				configChange = true;
 			}
 
@@ -508,8 +514,8 @@ void ApiListener::HandleConfigUpdate(const MessageOrigin::Ptr& origin, const Dic
 			<< "Applying configuration file update for path '" << stageConfigZoneDir << "' ("
 			<< numBytes << " Bytes).";
 
-		// If the update removes a path, delete it on disk and signal a config change.
-		{
+		if (timestampChanged) {
+			// If the update removes a path, delete it on disk and signal a config change.
 			ObjectLock xlock(productionConfig);
 
 			for (const Dictionary::Pair& kv : productionConfig) {


=====================================
lib/remote/apilistener.cpp
=====================================
@@ -679,19 +679,21 @@ void ApiListener::NewClientHandlerInternal(
 	if (ctype == ClientJsonRpc) {
 		Log(LogNotice, "ApiListener", "New JSON-RPC client");
 
+		if (endpoint && endpoint->GetConnected()) {
+			Log(LogNotice, "ApiListener")
+				<< "Ignoring JSON-RPC connection " << conninfo
+				<< ". We're already connected to Endpoint '" << endpoint->GetName() << "'.";
+			return;
+		}
+
 		JsonRpcConnection::Ptr aclient = new JsonRpcConnection(identity, verify_ok, client, role);
 
 		if (endpoint) {
-			bool needSync = !endpoint->GetConnected();
-
 			endpoint->AddClient(aclient);
 
-			IoEngine::SpawnCoroutine(IoEngine::Get().GetIoContext(), [this, aclient, endpoint, needSync](asio::yield_context yc) {
-				CpuBoundWork syncClient (yc);
-
-				SyncClient(aclient, endpoint, needSync);
+			Utility::QueueAsyncCallback([this, aclient, endpoint]() {
+				SyncClient(aclient, endpoint, true);
 			});
-
 		} else if (!AddAnonymousClient(aclient)) {
 			Log(LogNotice, "ApiListener")
 				<< "Ignoring anonymous JSON-RPC connection " << conninfo
@@ -1032,6 +1034,17 @@ void ApiListener::SyncSendMessage(const Endpoint::Ptr& endpoint, const Dictionar
 	}
 }
 
+/**
+ * Relay a message to a directly connected zone or to a global zone.
+ * If some other zone is passed as the target zone, it is not relayed.
+ *
+ * @param targetZone The zone to relay to
+ * @param origin Information about where this message is relayed from (if it was not generated locally)
+ * @param message The message to relay
+ * @param currentZoneMaster The current master node of the local zone
+ * @return true if the message has been relayed to all relevant endpoints,
+ *         false if it hasn't and must be persisted in the replay log
+ */
 bool ApiListener::RelayMessageOne(const Zone::Ptr& targetZone, const MessageOrigin::Ptr& origin, const Dictionary::Ptr& message, const Endpoint::Ptr& currentZoneMaster)
 {
 	ASSERT(targetZone);
@@ -1050,82 +1063,88 @@ bool ApiListener::RelayMessageOne(const Zone::Ptr& targetZone, const MessageOrig
 
 	std::vector<Endpoint::Ptr> skippedEndpoints;
 
-	bool relayed = false, log_needed = false, log_done = false;
-
-	std::set<Endpoint::Ptr> targetEndpoints;
-
+	std::set<Zone::Ptr> allTargetZones;
 	if (targetZone->GetGlobal()) {
-		targetEndpoints = localZone->GetEndpoints();
-
+		/* if the zone is global, the message has to be relayed to our local zone and direct children */
+		allTargetZones.insert(localZone);
 		for (const Zone::Ptr& zone : ConfigType::GetObjectsByType<Zone>()) {
-			/* Fetch immediate child zone members */
 			if (zone->GetParent() == localZone) {
-				std::set<Endpoint::Ptr> endpoints = zone->GetEndpoints();
-				targetEndpoints.insert(endpoints.begin(), endpoints.end());
+				allTargetZones.insert(zone);
 			}
 		}
 	} else {
-		targetEndpoints = targetZone->GetEndpoints();
+		/* whereas if it's not global, the message is just relayed to the zone itself */
+		allTargetZones.insert(targetZone);
 	}
 
-	for (const Endpoint::Ptr& targetEndpoint : targetEndpoints) {
-		/* Don't relay messages to ourselves. */
-		if (targetEndpoint == localEndpoint)
-			continue;
+	bool needsReplay = false;
 
-		log_needed = true;
+	for (const Zone::Ptr& currentTargetZone : allTargetZones) {
+		bool relayed = false, log_needed = false, log_done = false;
 
-		/* Don't relay messages to disconnected endpoints. */
-		if (!targetEndpoint->GetConnected()) {
-			if (targetZone == localZone)
-				log_done = false;
+		for (const Endpoint::Ptr& targetEndpoint : currentTargetZone->GetEndpoints()) {
+			/* Don't relay messages to ourselves. */
+			if (targetEndpoint == localEndpoint)
+				continue;
 
-			continue;
-		}
+			log_needed = true;
 
-		log_done = true;
+			/* Don't relay messages to disconnected endpoints. */
+			if (!targetEndpoint->GetConnected()) {
+				if (currentTargetZone == localZone)
+					log_done = false;
 
-		/* Don't relay the message to the zone through more than one endpoint unless this is our own zone.
-		 * 'relayed' is set to true on success below, enabling the checks in the second iteration.
-		 */
-		if (relayed && targetZone != localZone) {
-			skippedEndpoints.push_back(targetEndpoint);
-			continue;
-		}
+				continue;
+			}
 
-		/* Don't relay messages back to the endpoint which we got the message from. */
-		if (origin && origin->FromClient && targetEndpoint == origin->FromClient->GetEndpoint()) {
-			skippedEndpoints.push_back(targetEndpoint);
-			continue;
-		}
+			log_done = true;
 
-		/* Don't relay messages back to the zone which we got the message from. */
-		if (origin && origin->FromZone && targetZone == origin->FromZone) {
-			skippedEndpoints.push_back(targetEndpoint);
-			continue;
-		}
+			/* Don't relay the message to the zone through more than one endpoint unless this is our own zone.
+			 * 'relayed' is set to true on success below, enabling the checks in the second iteration.
+			 */
+			if (relayed && currentTargetZone != localZone) {
+				skippedEndpoints.push_back(targetEndpoint);
+				continue;
+			}
 
-		/* Only relay message to the zone master if we're not currently the zone master.
-		 * e1 is zone master, e2 and e3 are zone members.
-		 *
-		 * Message is sent from e2 or e3:
-		 *   !isMaster == true
-		 *   targetEndpoint e1 is zone master -> send the message
-		 *   targetEndpoint e3 is not zone master -> skip it, avoid routing loops
-		 *
-		 * Message is sent from e1:
-		 *   !isMaster == false -> send the messages to e2 and e3 being the zone routing master.
-		 */
-		bool isMaster = (currentZoneMaster == localEndpoint);
+			/* Don't relay messages back to the endpoint which we got the message from. */
+			if (origin && origin->FromClient && targetEndpoint == origin->FromClient->GetEndpoint()) {
+				skippedEndpoints.push_back(targetEndpoint);
+				continue;
+			}
 
-		if (!isMaster && targetEndpoint != currentZoneMaster) {
-			skippedEndpoints.push_back(targetEndpoint);
-			continue;
-		}
+			/* Don't relay messages back to the zone which we got the message from. */
+			if (origin && origin->FromZone && currentTargetZone == origin->FromZone) {
+				skippedEndpoints.push_back(targetEndpoint);
+				continue;
+			}
+
+			/* Only relay message to the zone master if we're not currently the zone master.
+			 * e1 is zone master, e2 and e3 are zone members.
+			 *
+			 * Message is sent from e2 or e3:
+			 *   !isMaster == true
+			 *   targetEndpoint e1 is zone master -> send the message
+			 *   targetEndpoint e3 is not zone master -> skip it, avoid routing loops
+			 *
+			 * Message is sent from e1:
+			 *   !isMaster == false -> send the messages to e2 and e3 being the zone routing master.
+			 */
+			bool isMaster = (currentZoneMaster == localEndpoint);
+
+			if (!isMaster && targetEndpoint != currentZoneMaster) {
+				skippedEndpoints.push_back(targetEndpoint);
+				continue;
+			}
 
-		relayed = true;
+			relayed = true;
 
-		SyncSendMessage(targetEndpoint, message);
+			SyncSendMessage(targetEndpoint, message);
+		}
+
+		if (log_needed && !log_done) {
+			needsReplay = true;
+		}
 	}
 
 	if (!skippedEndpoints.empty()) {
@@ -1135,7 +1154,7 @@ bool ApiListener::RelayMessageOne(const Zone::Ptr& targetZone, const MessageOrig
 			skippedEndpoint->SetLocalLogPosition(ts);
 	}
 
-	return !log_needed || log_done;
+	return !needsReplay;
 }
 
 void ApiListener::SyncRelayMessage(const MessageOrigin::Ptr& origin,


=====================================
lib/remote/httpserverconnection.cpp
=====================================
@@ -539,12 +539,16 @@ void HttpServerConnection::ProcessMessages(boost::asio::yield_context yc)
 				authenticatedUser = ApiUser::GetByAuthHeader(request[http::field::authorization].to_string());
 			}
 
-			Log(LogInformation, "HttpServerConnection")
-				<< "Request: " << request.method_string() << ' ' << request.target()
+			Log logMsg (LogInformation, "HttpServerConnection");
+
+			logMsg << "Request: " << request.method_string() << ' ' << request.target()
 				<< " (from " << m_PeerAddress
 				<< "), user: " << (authenticatedUser ? authenticatedUser->GetName() : "<unauthenticated>")
-				<< ", agent: " << request[http::field::user_agent] << ")."; //operator[] - Returns the value for a field, or "" if it does not exist.
+				<< ", agent: " << request[http::field::user_agent]; //operator[] - Returns the value for a field, or "" if it does not exist.
 
+			Defer addRespCode ([&response, &logMsg]() {
+				logMsg << ", status: " << response.result() << ").";
+			});
 
 			if (!HandleAccessControl(*m_Stream, request, response, yc)) {
 				break;


=====================================
lib/remote/jsonrpcconnection.cpp
=====================================
@@ -348,20 +348,43 @@ void JsonRpcConnection::CheckLiveness(boost::asio::yield_context yc)
 {
 	boost::system::error_code ec;
 
-	for (;;) {
-		m_CheckLivenessTimer.expires_from_now(boost::posix_time::seconds(30));
+	if (!m_Authenticated) {
+		/* Anonymous connections are normally only used for requesting a certificate and are closed after this request
+		 * is received. However, the request is only sent if the child has successfully verified the certificate of its
+		 * parent so that it is an authenticated connection from its perspective. In case this verification fails, both
+		 * ends view it as an anonymous connection and never actually use it but attempt a reconnect after 10 seconds
+		 * leaking the connection. Therefore close it after a timeout.
+		 */
+
+		m_CheckLivenessTimer.expires_from_now(boost::posix_time::seconds(10));
 		m_CheckLivenessTimer.async_wait(yc[ec]);
 
 		if (m_ShuttingDown) {
-			break;
+			return;
 		}
 
-		if (m_Seen < Utility::GetTime() - 60 && (!m_Endpoint || !m_Endpoint->GetSyncing())) {
-			Log(LogInformation, "JsonRpcConnection")
-				<<  "No messages for identity '" << m_Identity << "' have been received in the last 60 seconds.";
+		auto remote (m_Stream->lowest_layer().remote_endpoint());
 
-			Disconnect();
-			break;
+		Log(LogInformation, "JsonRpcConnection")
+			<< "Closing anonymous connection [" << remote.address() << "]:" << remote.port() << " after 10 seconds.";
+
+		Disconnect();
+	} else {
+		for (;;) {
+			m_CheckLivenessTimer.expires_from_now(boost::posix_time::seconds(30));
+			m_CheckLivenessTimer.async_wait(yc[ec]);
+
+			if (m_ShuttingDown) {
+				break;
+			}
+
+			if (m_Seen < Utility::GetTime() - 60 && (!m_Endpoint || !m_Endpoint->GetSyncing())) {
+				Log(LogInformation, "JsonRpcConnection")
+					<<  "No messages for identity '" << m_Identity << "' have been received in the last 60 seconds.";
+
+				Disconnect();
+				break;
+			}
 		}
 	}
 }



View it on GitLab: https://salsa.debian.org/nagios-team/pkg-icinga2/-/compare/3bc257cbb19ce27799bcdac2d93c8e7510ee660f...3c21532fdb340248aef25d626c911ee4bd20b9d3

-- 
View it on GitLab: https://salsa.debian.org/nagios-team/pkg-icinga2/-/compare/3bc257cbb19ce27799bcdac2d93c8e7510ee660f...3c21532fdb340248aef25d626c911ee4bd20b9d3
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-nagios-changes/attachments/20201126/51b9c48d/attachment-0001.html>


More information about the pkg-nagios-changes mailing list