Skip to content
Commits on Source (4)
......@@ -31,6 +31,7 @@ Christian Jonak <christian@jonak.org>
Christian Lehmann <christian_lehmann@gmx.de>
Christian Loos <cloos@netsandbox.de>
Christian Schmidt <github@chsc.dk>
Christopher Schirner <schinken@bamberg.ccc.de>
Claudio Bilotta <bilottalove@gmail.com>
Claudio Kuenzler <ck@claudiokuenzler.com>
Conrad Clement <cclement@printeron.com>
......
# Icinga 2.x CHANGELOG
## 2.9.2 (2018-09-26)
### Enhancement
* [#6602](https://github.com/icinga/icinga2/issues/6602) (API, Cluster, PR): Improve TLS handshake exception logging
* [#6568](https://github.com/icinga/icinga2/issues/6568) (Configuration, PR): Ensure that config object types are committed in dependent load order
* [#6497](https://github.com/icinga/icinga2/issues/6497) (Configuration, PR): Improve error logging for match/regex/cidr\_match functions and unsupported dictionary usage
### Bug
* [#6596](https://github.com/icinga/icinga2/issues/6596) (Crash, PR): Fix crash on API queries with Fedora 28 hardening and GCC 8
* [#6581](https://github.com/icinga/icinga2/issues/6581) (Configuration, PR): Shuffle items before config validation
* [#6569](https://github.com/icinga/icinga2/issues/6569) (DB IDO): Custom Vars not updated after upgrade
* [#6533](https://github.com/icinga/icinga2/issues/6533) (Crash): Icinga2 crashes after using some api-commands on Fedora 28
* [#6505](https://github.com/icinga/icinga2/issues/6505) (Cluster, PR): Fix clusterzonecheck if not connected
* [#6498](https://github.com/icinga/icinga2/issues/6498) (Configuration, PR): Fix regression with MatchAny false conditions on match/regex/cidr\_match
* [#6496](https://github.com/icinga/icinga2/issues/6496) (Configuration): error with match and type matchany
### Documentation
* [#6590](https://github.com/icinga/icinga2/issues/6590) (DB IDO, Documentation, PR): Update workaround for custom vars
* [#6572](https://github.com/icinga/icinga2/issues/6572) (Documentation, PR): Add note about workaround for broken custom vars
### Support
* [#6540](https://github.com/icinga/icinga2/issues/6540) (Configuration): Evaluate a fixed config compiler commit order
* [#6486](https://github.com/icinga/icinga2/issues/6486) (Configuration): Configuration validation w/ ScheduledDowntimes performance decreased in 2.9
* [#6442](https://github.com/icinga/icinga2/issues/6442) (Configuration): Error while evaluating "assign where match" expression: std::bad\_cast
## 2.9.1 (2018-07-24)
### Bug
......
......@@ -26,7 +26,7 @@
Specify the release version.
```
VERSION=2.9.0
VERSION=2.9.2
```
Add your signing key to your Git configuration file, if not already there.
......@@ -60,10 +60,11 @@ git log --use-mailmap | grep '^Author:' | cut -f2- -d' ' | sort | uniq > AUTHORS
## Version <a id="version"></a>
Update the version in the version file:
Update the version:
```
sed -i "s/Version: .*/Version: $VERSION/g" VERSION
sed -i "s/VERSION=.*/VERSION=$VERSION/g" RELEASE.md
```
## Changelog <a id="changelog"></a>
......
Version: 2.9.1
Version: 2.9.2
Revision: 1
icinga2 (2.9.1-2) UNRELEASED; urgency=medium
icinga2 (2.9.2-1) unstable; urgency=medium
* Team upload.
* New upstream release.
* Bump Standards-Version to 4.2.1, no changes.
-- Bas Couwenberg <sebastic@debian.org> Sun, 05 Aug 2018 21:09:23 +0200
-- Bas Couwenberg <sebastic@debian.org> Fri, 28 Sep 2018 07:32:37 +0200
icinga2 (2.9.1-1) unstable; urgency=medium
......
......@@ -97,6 +97,24 @@ With the removal of RHEL 5 as supported platform, we can finally use real unique
This is reflected in generating names for e.g. API stage names. Previously it was a handcrafted
mix of local FQDN, timestamps and random numbers.
### Custom Vars not updating <a id="upgrading-to-2-9-custom-vars-not-updating"></a>
A rare issue preventing the custom vars of objects created prior to 2.9.0 being updated when changed may occur. To
remedy this, truncate the customvar tables and restart Icinga 2. The following is an example of how to do this with mysql:
```
$ mysql -uroot -picinga icinga
MariaDB [icinga]> truncate icinga_customvariables;
Query OK, 0 rows affected (0.05 sec)
MariaDB [icinga]> truncate icinga_customvariablestatus;
Query OK, 0 rows affected (0.03 sec)
MariaDB [icinga]> exit
Bye
$ sudo systemctl restart icinga2
```
Custom vars should now stay up to date.
## Upgrading to v2.8.2 <a id="upgrading-to-2-8-2"></a>
......
......@@ -108,10 +108,14 @@ bool ScriptUtils::CastBool(const Value& value)
bool ScriptUtils::Regex(const std::vector<Value>& args)
{
if (args.size() < 2)
BOOST_THROW_EXCEPTION(std::invalid_argument("Regular expression and text must be specified."));
BOOST_THROW_EXCEPTION(std::invalid_argument("Regular expression and text must be specified for regex()."));
String pattern = args[0];
const Value& argTexts = args[1];
if (argTexts.IsObjectType<Dictionary>())
BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionaries are not supported by regex()."));
MatchType mode;
if (args.size() > 2)
......@@ -147,7 +151,8 @@ bool ScriptUtils::Regex(const std::vector<Value>& args)
return false;
}
return true;
/* MatchAny: Nothing matched. MatchAll: Everything matched. */
return mode == MatchAll;
} else {
String text = argTexts;
boost::smatch what;
......@@ -158,10 +163,14 @@ bool ScriptUtils::Regex(const std::vector<Value>& args)
bool ScriptUtils::Match(const std::vector<Value>& args)
{
if (args.size() < 2)
BOOST_THROW_EXCEPTION(std::invalid_argument("Pattern and text must be specified."));
BOOST_THROW_EXCEPTION(std::invalid_argument("Pattern and text must be specified for match()."));
String pattern = args[0];
const Value& argTexts = args[1];
if (argTexts.IsObjectType<Dictionary>())
BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionaries are not supported by match()."));
MatchType mode;
if (args.size() > 2)
......@@ -189,7 +198,8 @@ bool ScriptUtils::Match(const std::vector<Value>& args)
return false;
}
return true;
/* MatchAny: Nothing matched. MatchAll: Everything matched. */
return mode == MatchAll;
} else {
String text = argTexts;
return Utility::Match(pattern, argTexts);
......@@ -199,10 +209,14 @@ bool ScriptUtils::Match(const std::vector<Value>& args)
bool ScriptUtils::CidrMatch(const std::vector<Value>& args)
{
if (args.size() < 2)
BOOST_THROW_EXCEPTION(std::invalid_argument("CIDR and IP address must be specified."));
BOOST_THROW_EXCEPTION(std::invalid_argument("CIDR and IP address must be specified for cidr_match()."));
String pattern = args[0];
const Value& argIps = args[1];
if (argIps.IsObjectType<Dictionary>())
BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionaries are not supported by cidr_match()."));
MatchType mode;
if (args.size() > 2)
......@@ -230,7 +244,8 @@ bool ScriptUtils::CidrMatch(const std::vector<Value>& args)
return false;
}
return true;
/* MatchAny: Nothing matched. MatchAll: Everything matched. */
return mode == MatchAll;
} else {
String ip = argIps;
return Utility::CidrMatch(pattern, ip);
......
......@@ -38,6 +38,8 @@
#include "base/function.hpp"
#include <sstream>
#include <fstream>
#include <algorithm>
#include <random>
using namespace icinga;
......@@ -428,26 +430,77 @@ bool ConfigItem::CommitNewItems(const ActivationContext::Ptr& context, WorkQueue
if (items.empty())
return true;
// Shuffle all items to evenly distribute them over the threads of the workqueue. This increases perfomance
// noticably in environments with lots of objects and available threads.
std::shuffle(std::begin(items), std::end(items), std::default_random_engine {});
#ifdef I2_DEBUG
Log(LogDebug, "configitem")
<< "Committing " << items.size() << " new items.";
#endif /* I2_DEBUG */
for (const auto& ip : items)
newItems.push_back(ip.first);
upq.ParallelFor(items, [](const ItemPair& ip) {
std::set<Type::Ptr> types;
std::set<Type::Ptr> completed_types;
for (const Type::Ptr& type : Type::GetAllTypes()) {
if (ConfigObject::TypeInstance->IsAssignableFrom(type))
types.insert(type);
}
while (types.size() != completed_types.size()) {
for (const Type::Ptr& type : types) {
if (completed_types.find(type) != completed_types.end())
continue;
bool unresolved_dep = false;
/* skip this type (for now) if there are unresolved load dependencies */
for (const String& loadDep : type->GetLoadDependencies()) {
Type::Ptr pLoadDep = Type::GetByName(loadDep);
if (types.find(pLoadDep) != types.end() && completed_types.find(pLoadDep) == completed_types.end()) {
unresolved_dep = true;
break;
}
}
if (unresolved_dep)
continue;
int committed_items = 0;
upq.ParallelFor(items, [&type, &committed_items](const ItemPair& ip) {
const ConfigItem::Ptr& item = ip.first;
if (item->m_Type != type)
return;
ip.first->Commit(ip.second);
committed_items++;
});
upq.Join();
if (upq.HasExceptions())
return false;
completed_types.insert(type);
std::set<Type::Ptr> types;
#ifdef I2_DEBUG
if (committed_items > 0)
Log(LogDebug, "configitem")
<< "Committed " << committed_items << " items of type '" << type->GetName() << "'.";
#endif /* I2_DEBUG */
for (const Type::Ptr& type : Type::GetAllTypes()) {
if (ConfigObject::TypeInstance->IsAssignableFrom(type))
types.insert(type);
if (upq.HasExceptions())
return false;
}
}
std::set<Type::Ptr> completed_types;
#ifdef I2_DEBUG
Log(LogDebug, "configitem")
<< "Committed " << items.size() << " items.";
#endif /* I2_DEBUG */
completed_types.clear();
while (types.size() != completed_types.size()) {
for (const Type::Ptr& type : types) {
......@@ -468,7 +521,8 @@ bool ConfigItem::CommitNewItems(const ActivationContext::Ptr& context, WorkQueue
if (unresolved_dep)
continue;
upq.ParallelFor(items, [&type](const ItemPair& ip) {
int notified_items = 0;
upq.ParallelFor(items, [&type, &notified_items](const ItemPair& ip) {
const ConfigItem::Ptr& item = ip.first;
if (!item->m_Object || item->m_Type != type)
......@@ -476,6 +530,7 @@ bool ConfigItem::CommitNewItems(const ActivationContext::Ptr& context, WorkQueue
try {
item->m_Object->OnAllConfigLoaded();
notified_items++;
} catch (const std::exception& ex) {
if (!item->m_IgnoreOnError)
throw;
......@@ -496,11 +551,18 @@ bool ConfigItem::CommitNewItems(const ActivationContext::Ptr& context, WorkQueue
upq.Join();
#ifdef I2_DEBUG
if (notified_items > 0)
Log(LogDebug, "configitem")
<< "Sent OnAllConfigLoaded to " << notified_items << " items of type '" << type->GetName() << "'.";
#endif /* I2_DEBUG */
if (upq.HasExceptions())
return false;
notified_items = 0;
for (const String& loadDep : type->GetLoadDependencies()) {
upq.ParallelFor(items, [loadDep, &type](const ItemPair& ip) {
upq.ParallelFor(items, [loadDep, &type, &notified_items](const ItemPair& ip) {
const ConfigItem::Ptr& item = ip.first;
if (!item->m_Object || item->m_Type->GetName() != loadDep)
......@@ -508,14 +570,22 @@ bool ConfigItem::CommitNewItems(const ActivationContext::Ptr& context, WorkQueue
ActivationScope ascope(item->m_ActivationContext);
item->m_Object->CreateChildObjects(type);
notified_items++;
});
}
upq.Join();
#ifdef I2_DEBUG
if (notified_items > 0)
Log(LogDebug, "configitem")
<< "Sent CreateChildObjects to " << notified_items << " items of type '" << type->GetName() << "'.";
#endif /* I2_DEBUG */
if (upq.HasExceptions())
return false;
// Make sure to activate any additionally generated items
if (!CommitNewItems(context, upq, newItems))
return false;
}
......
......@@ -122,13 +122,9 @@ void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const Che
bytesReceivedPerSecond += endpoint->GetBytesReceivedPerSecond();
}
if (!connected) {
cr->SetState(ServiceCritical);
cr->SetOutput("Zone '" + zoneName + "' is not connected. Log lag: " + Utility::FormatDuration(zoneLag));
} else {
if (connected) {
cr->SetState(ServiceOK);
cr->SetOutput("Zone '" + zoneName + "' is connected. Log lag: " + Utility::FormatDuration(zoneLag));
}
/* Check whether the thresholds have been resolved and compare them */
if (missingLagCritical.IsEmpty() && zoneLag > lagCritical) {
......@@ -140,6 +136,10 @@ void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const Che
cr->SetOutput("Zone '" + zoneName + "' is connected. Log lag: " + Utility::FormatDuration(zoneLag)
+ " greater than warning threshold: " + Utility::FormatDuration(lagWarning));
}
} else {
cr->SetState(ServiceCritical);
cr->SetOutput("Zone '" + zoneName + "' is not connected. Log lag: " + Utility::FormatDuration(zoneLag));
}
cr->SetPerformanceData(new Array({
new PerfdataValue("slave_lag", zoneLag, false, "s", lagWarning, lagCritical),
......
......@@ -434,7 +434,7 @@ void ElasticsearchWriter::SendRequest(const String& body)
stream = Connect();
} catch (const std::exception& ex) {
Log(LogWarning, "ElasticsearchWriter")
<< "Flush failed, cannot connect to Elasticsearch.";
<< "Flush failed, cannot connect to Elasticsearch: " << DiagnosticInformation(ex, false);
return;
}
......
......@@ -425,7 +425,7 @@ void InfluxdbWriter::Flush()
stream = Connect();
} catch (const std::exception& ex) {
Log(LogWarning, "InfluxDbWriter")
<< "Flush failed, cannot connect to InfluxDB.";
<< "Flush failed, cannot connect to InfluxDB: " << DiagnosticInformation(ex, false);
return;
}
......
......@@ -454,9 +454,9 @@ void ApiListener::NewClientHandlerInternal(const Socket::Ptr& client, const Stri
try {
tlsStream->Handshake();
} catch (const std::exception&) {
} catch (const std::exception& ex) {
Log(LogCritical, "ApiListener")
<< "Client TLS handshake failed (" << conninfo << ")";
<< "Client TLS handshake failed (" << conninfo << "): " << DiagnosticInformation(ex, false);
tlsStream->Close();
return;
}
......
......@@ -127,7 +127,7 @@ static void FilteredAddTarget(ScriptFrame& permissionFrame, Expression *permissi
ScriptFrame& frame, Expression *ufilter, std::vector<Value>& result, const String& variableName, const Object::Ptr& target)
{
if (FilterUtility::EvaluateFilter(permissionFrame, permissionFilter, target, variableName) && FilterUtility::EvaluateFilter(frame, ufilter, target, variableName))
result.emplace_back(target);
result.emplace_back(std::move(target));
}
void FilterUtility::CheckPermission(const ApiUser::Ptr& user, const String& permission, Expression **permissionFilter)
......@@ -206,7 +206,7 @@ std::vector<Value> FilterUtility::GetFilterTargets(const QueryDescription& qd, c
if (attr == "type")
attr = "name";
if (query->Contains(attr)) {
if (query && query->Contains(attr)) {
String name = HttpUtility::GetLastParameter(query, attr);
Object::Ptr target = provider->GetTargetByName(type, name);
......@@ -219,7 +219,7 @@ std::vector<Value> FilterUtility::GetFilterTargets(const QueryDescription& qd, c
attr = provider->GetPluralName(type);
boost::algorithm::to_lower(attr);
if (query->Contains(attr)) {
if (query && query->Contains(attr)) {
Array::Ptr names = query->Get(attr);
if (names) {
ObjectLock olock(names);
......@@ -235,7 +235,7 @@ std::vector<Value> FilterUtility::GetFilterTargets(const QueryDescription& qd, c
}
}
if (query->Contains("filter") || result.empty()) {
if ((query && query->Contains("filter")) || result.empty()) {
if (!query->Contains("type"))
BOOST_THROW_EXCEPTION(std::invalid_argument("Type must be specified when using a filter."));
......@@ -251,12 +251,9 @@ std::vector<Value> FilterUtility::GetFilterTargets(const QueryDescription& qd, c
frame.Sandboxed = true;
Dictionary::Ptr uvars = new Dictionary();
std::unique_ptr<Expression> ufilter;
if (query->Contains("filter")) {
String filter = HttpUtility::GetLastParameter(query, "filter");
ufilter = ConfigCompiler::CompileText("<API query>", filter);
}
std::unique_ptr<Expression> ufilter = ConfigCompiler::CompileText("<API query>", filter);
Dictionary::Ptr filter_vars = query->Get("filter_vars");
if (filter_vars) {
......@@ -271,6 +268,14 @@ std::vector<Value> FilterUtility::GetFilterTargets(const QueryDescription& qd, c
provider->FindTargets(type, std::bind(&FilteredAddTarget,
std::ref(permissionFrame), permissionFilter,
std::ref(frame), &*ufilter, std::ref(result), variableName, _1));
} else {
/* Ensure to pass a nullptr as filter expression.
* GCC 8.1.1 on F28 causes problems, see GH #6533.
*/
provider->FindTargets(type, std::bind(&FilteredAddTarget,
std::ref(permissionFrame), permissionFilter,
std::ref(frame), nullptr, std::ref(result), variableName, _1));
}
}
return result;
......
......@@ -187,8 +187,9 @@ int PkiUtility::RequestCertificate(const String& host, const String& port, const
try {
stream->Handshake();
} catch (const std::exception&) {
Log(LogCritical, "cli", "Client TLS handshake failed.");
} catch (const std::exception& ex) {
Log(LogCritical, "cli")
<< "Client TLS handshake failed: " << DiagnosticInformation(ex, false);
return 1;
}
......
......@@ -21,6 +21,7 @@
#define PKIUTILITY_H
#include "remote/i2-remote.hpp"
#include "base/exception.hpp"
#include "base/dictionary.hpp"
#include "base/string.hpp"
#include <openssl/x509v3.h>
......