mirror of https://github.com/Icinga/icinga2.git
parent
6e70e2ddf0
commit
0b466aabc0
|
@ -591,6 +591,46 @@ String PBKDF2_SHA1(const String& password, const String& salt, int iterations)
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String SHA1(const String& s, bool binary)
|
||||||
|
{
|
||||||
|
char errbuf[120];
|
||||||
|
SHA_CTX context;
|
||||||
|
unsigned char digest[SHA_DIGEST_LENGTH];
|
||||||
|
|
||||||
|
if (!SHA1_Init(&context)) {
|
||||||
|
Log(LogCritical, "SSL")
|
||||||
|
<< "Error on SHA Init: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
|
||||||
|
BOOST_THROW_EXCEPTION(openssl_error()
|
||||||
|
<< boost::errinfo_api_function("SHA1_Init")
|
||||||
|
<< errinfo_openssl_error(ERR_peek_error()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SHA1_Update(&context, (unsigned char*)s.CStr(), s.GetLength())) {
|
||||||
|
Log(LogCritical, "SSL")
|
||||||
|
<< "Error on SHA Update: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
|
||||||
|
BOOST_THROW_EXCEPTION(openssl_error()
|
||||||
|
<< boost::errinfo_api_function("SHA1_Update")
|
||||||
|
<< errinfo_openssl_error(ERR_peek_error()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SHA1_Final(digest, &context)) {
|
||||||
|
Log(LogCritical, "SSL")
|
||||||
|
<< "Error on SHA Final: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
|
||||||
|
BOOST_THROW_EXCEPTION(openssl_error()
|
||||||
|
<< boost::errinfo_api_function("SHA1_Final")
|
||||||
|
<< errinfo_openssl_error(ERR_peek_error()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (binary)
|
||||||
|
return String(reinterpret_cast<const char*>(digest));
|
||||||
|
|
||||||
|
char output[SHA_DIGEST_LENGTH*2+1];
|
||||||
|
for (int i = 0; i < 20; i++)
|
||||||
|
sprintf(output + 2 * i, "%02x", digest[i]);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
String SHA256(const String& s)
|
String SHA256(const String& s)
|
||||||
{
|
{
|
||||||
char errbuf[120];
|
char errbuf[120];
|
||||||
|
|
|
@ -50,7 +50,7 @@ String I2_BASE_API GetIcingaCADir(void);
|
||||||
String I2_BASE_API CertificateToString(const boost::shared_ptr<X509>& cert);
|
String I2_BASE_API CertificateToString(const boost::shared_ptr<X509>& cert);
|
||||||
boost::shared_ptr<X509> I2_BASE_API CreateCertIcingaCA(EVP_PKEY *pubkey, X509_NAME *subject);
|
boost::shared_ptr<X509> I2_BASE_API CreateCertIcingaCA(EVP_PKEY *pubkey, X509_NAME *subject);
|
||||||
String I2_BASE_API PBKDF2_SHA1(const String& password, const String& salt, int iterations);
|
String I2_BASE_API PBKDF2_SHA1(const String& password, const String& salt, int iterations);
|
||||||
String I2_BASE_API SHA1(const String& s);
|
String I2_BASE_API SHA1(const String& s, bool binary = false);
|
||||||
String I2_BASE_API SHA256(const String& s);
|
String I2_BASE_API SHA256(const String& s);
|
||||||
String I2_BASE_API RandomString(int length);
|
String I2_BASE_API RandomString(int length);
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
mkclass_target(rediswriter.ti rediswriter.tcpp rediswriter.thpp)
|
mkclass_target(rediswriter.ti rediswriter.tcpp rediswriter.thpp)
|
||||||
|
|
||||||
set(redis_SOURCES
|
set(redis_SOURCES
|
||||||
rediswriter.cpp rediswriter-config.cpp rediswriter.thpp
|
rediswriter.cpp rediswriter-config.cpp rediswriter-utility.cpp rediswriter.thpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if(ICINGA2_UNITY_BUILD)
|
if(ICINGA2_UNITY_BUILD)
|
||||||
|
|
|
@ -19,9 +19,12 @@
|
||||||
|
|
||||||
#include "redis/rediswriter.hpp"
|
#include "redis/rediswriter.hpp"
|
||||||
#include "icinga/customvarobject.hpp"
|
#include "icinga/customvarobject.hpp"
|
||||||
|
#include "icinga/host.hpp"
|
||||||
|
#include "icinga/service.hpp"
|
||||||
#include "base/json.hpp"
|
#include "base/json.hpp"
|
||||||
#include "base/logger.hpp"
|
#include "base/logger.hpp"
|
||||||
#include "base/serializer.hpp"
|
#include "base/serializer.hpp"
|
||||||
|
#include "base/tlsutility.hpp"
|
||||||
#include "base/initialize.hpp"
|
#include "base/initialize.hpp"
|
||||||
|
|
||||||
using namespace icinga;
|
using namespace icinga;
|
||||||
|
@ -52,12 +55,10 @@ void RedisWriter::ConfigStaticInitialize(void)
|
||||||
ConfigObject::OnVersionChanged.connect(boost::bind(&RedisWriter::VersionChangedHandler, _1));
|
ConfigObject::OnVersionChanged.connect(boost::bind(&RedisWriter::VersionChangedHandler, _1));
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: OnActiveChanged handling.
|
|
||||||
void RedisWriter::UpdateAllConfigObjects(void)
|
void RedisWriter::UpdateAllConfigObjects(void)
|
||||||
{
|
{
|
||||||
AssertOnWorkQueue();
|
AssertOnWorkQueue();
|
||||||
|
|
||||||
//TODO: Just use config types
|
|
||||||
for (const Type::Ptr& type : Type::GetAllTypes()) {
|
for (const Type::Ptr& type : Type::GetAllTypes()) {
|
||||||
if (!ConfigObject::TypeInstance->IsAssignableFrom(type))
|
if (!ConfigObject::TypeInstance->IsAssignableFrom(type))
|
||||||
continue;
|
continue;
|
||||||
|
@ -108,25 +109,62 @@ void RedisWriter::SendConfigUpdate(const ConfigObject::Ptr& object, const String
|
||||||
//TODO: checksum
|
//TODO: checksum
|
||||||
String objectName = object->GetName();
|
String objectName = object->GetName();
|
||||||
|
|
||||||
redisReply *reply = reinterpret_cast<redisReply *>(redisCommand(m_Context, "HSET icinga:config:%s %s %s", typeName.CStr(), objectName.CStr(), jsonBody.CStr()));
|
redisReply *reply1 = reinterpret_cast<redisReply *>(redisCommand(m_Context, "HSET icinga:config:%s %s %s", typeName.CStr(), objectName.CStr(), jsonBody.CStr()));
|
||||||
|
|
||||||
if (!reply) {
|
if (!reply1) {
|
||||||
redisFree(m_Context);
|
redisFree(m_Context);
|
||||||
m_Context = NULL;
|
m_Context = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reply->type == REDIS_REPLY_STATUS || reply->type == REDIS_REPLY_ERROR) {
|
if (reply1->type == REDIS_REPLY_STATUS || reply1->type == REDIS_REPLY_ERROR) {
|
||||||
Log(LogInformation, "RedisWriter")
|
Log(LogInformation, "RedisWriter")
|
||||||
<< "HSET icinga:config:" << typeName << " " << objectName << " " << jsonBody << ": " << reply->str;
|
<< "HSET icinga:config:" << typeName << " " << objectName << " " << jsonBody << ": " << reply1->str;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reply->type == REDIS_REPLY_ERROR) {
|
if (reply1->type == REDIS_REPLY_ERROR) {
|
||||||
freeReplyObject(reply);
|
freeReplyObject(reply1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
freeReplyObject(reply);
|
freeReplyObject(reply1);
|
||||||
|
|
||||||
|
|
||||||
|
/* check sums */
|
||||||
|
/* hset icinga:config:Host:checksums localhost { "name_checksum": "...", "properties_checksum": "...", "groups_checksum": "...", "vars_checksum": null } */
|
||||||
|
Dictionary::Ptr checkSum = new Dictionary();
|
||||||
|
|
||||||
|
checkSum->Set("name_checksum", CalculateCheckSumString(object->GetName()));
|
||||||
|
|
||||||
|
if (object->GetReflectionType() == Host::TypeInstance) {
|
||||||
|
Host::Ptr host = static_pointer_cast<Host>(object);
|
||||||
|
checkSum->Set("groups_checksum", CalculateCheckSumGroups(host->GetGroups()));
|
||||||
|
} else if (object->GetReflectionType() == Service::TypeInstance) {
|
||||||
|
Service::Ptr service = static_pointer_cast<Service>(object);
|
||||||
|
checkSum->Set("groups_checksum", CalculateCheckSumGroups(service->GetGroups()));
|
||||||
|
}
|
||||||
|
|
||||||
|
String checkSumBody = JsonEncode(checkSum);
|
||||||
|
|
||||||
|
redisReply *reply2 = reinterpret_cast<redisReply *>(redisCommand(m_Context, "HSET icinga:config:%s:checksum %s %s", typeName.CStr(), objectName.CStr(), checkSumBody.CStr()));
|
||||||
|
|
||||||
|
if (!reply2) {
|
||||||
|
redisFree(m_Context);
|
||||||
|
m_Context = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reply2->type == REDIS_REPLY_STATUS || reply2->type == REDIS_REPLY_ERROR) {
|
||||||
|
Log(LogInformation, "RedisWriter")
|
||||||
|
<< "HSET icinga:config:" << typeName << " " << objectName << " " << jsonBody << ": " << reply2->str;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reply2->type == REDIS_REPLY_ERROR) {
|
||||||
|
freeReplyObject(reply2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeReplyObject(reply2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedisWriter::SendStatusUpdate(const ConfigObject::Ptr& object, const String& typeName)
|
void RedisWriter::SendStatusUpdate(const ConfigObject::Ptr& object, const String& typeName)
|
||||||
|
@ -162,41 +200,6 @@ void RedisWriter::SendStatusUpdate(const ConfigObject::Ptr& object, const String
|
||||||
freeReplyObject(reply);
|
freeReplyObject(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary::Ptr RedisWriter::SerializeObjectAttrs(const Object::Ptr& object, int fieldType)
|
|
||||||
{
|
|
||||||
Type::Ptr type = object->GetReflectionType();
|
|
||||||
|
|
||||||
std::vector<int> fids;
|
|
||||||
|
|
||||||
for (int fid = 0; fid < type->GetFieldCount(); fid++) {
|
|
||||||
fids.push_back(fid);
|
|
||||||
}
|
|
||||||
|
|
||||||
Dictionary::Ptr resultAttrs = new Dictionary();
|
|
||||||
|
|
||||||
for (int& fid : fids) {
|
|
||||||
Field field = type->GetFieldInfo(fid);
|
|
||||||
|
|
||||||
if ((field.Attributes & fieldType) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Value val = object->GetField(fid);
|
|
||||||
|
|
||||||
/* hide attributes which shouldn't be user-visible */
|
|
||||||
if (field.Attributes & FANoUserView)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* hide internal navigation fields */
|
|
||||||
if (field.Attributes & FANavigation && !(field.Attributes & (FAConfig | FAState)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Value sval = Serialize(val);
|
|
||||||
resultAttrs->Set(field.Name, sval);
|
|
||||||
}
|
|
||||||
|
|
||||||
return resultAttrs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RedisWriter::StateChangedHandler(const ConfigObject::Ptr& object)
|
void RedisWriter::StateChangedHandler(const ConfigObject::Ptr& object)
|
||||||
{
|
{
|
||||||
Type::Ptr type = object->GetReflectionType();
|
Type::Ptr type = object->GetReflectionType();
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Icinga 2 *
|
||||||
|
* Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or *
|
||||||
|
* modify it under the terms of the GNU General Public License *
|
||||||
|
* as published by the Free Software Foundation; either version 2 *
|
||||||
|
* of the License, or (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the Free Software Foundation *
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "redis/rediswriter.hpp"
|
||||||
|
#include "icinga/customvarobject.hpp"
|
||||||
|
#include "base/json.hpp"
|
||||||
|
#include "base/logger.hpp"
|
||||||
|
#include "base/serializer.hpp"
|
||||||
|
#include "base/tlsutility.hpp"
|
||||||
|
#include "base/initialize.hpp"
|
||||||
|
|
||||||
|
using namespace icinga;
|
||||||
|
|
||||||
|
String RedisWriter::FormatCheckSumBinary(const String& str)
|
||||||
|
{
|
||||||
|
char output[20*2+1];
|
||||||
|
for (int i = 0; i < 20; i++)
|
||||||
|
sprintf(output + 2 * i, "%02x", str[i]);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
String RedisWriter::CalculateCheckSumString(const String& str)
|
||||||
|
{
|
||||||
|
return SHA1(str, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
String RedisWriter::CalculateCheckSumGroups(const Array::Ptr& groups)
|
||||||
|
{
|
||||||
|
String output;
|
||||||
|
|
||||||
|
bool first = true;
|
||||||
|
|
||||||
|
for (const String& group : groups) {
|
||||||
|
if (first)
|
||||||
|
first = false;
|
||||||
|
else
|
||||||
|
output += ";";
|
||||||
|
|
||||||
|
output += SHA1(group, true); //binary checksum required here
|
||||||
|
}
|
||||||
|
|
||||||
|
return SHA1(output, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
String RedisWriter::CalculateCheckSumAttrs(const Dictionary::Ptr& attrs)
|
||||||
|
{
|
||||||
|
String output;
|
||||||
|
|
||||||
|
//TODO: Implement
|
||||||
|
for (const Dictionary::Pair& kv: attrs) {
|
||||||
|
if (kv.second.IsNumber()) {
|
||||||
|
//use a precision of 6 for floating point numbers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary::Ptr RedisWriter::SerializeObjectAttrs(const Object::Ptr& object, int fieldType)
|
||||||
|
{
|
||||||
|
Type::Ptr type = object->GetReflectionType();
|
||||||
|
|
||||||
|
std::vector<int> fids;
|
||||||
|
|
||||||
|
for (int fid = 0; fid < type->GetFieldCount(); fid++) {
|
||||||
|
fids.push_back(fid);
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary::Ptr resultAttrs = new Dictionary();
|
||||||
|
|
||||||
|
for (int& fid : fids) {
|
||||||
|
Field field = type->GetFieldInfo(fid);
|
||||||
|
|
||||||
|
if ((field.Attributes & fieldType) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Value val = object->GetField(fid);
|
||||||
|
|
||||||
|
/* hide attributes which shouldn't be user-visible */
|
||||||
|
if (field.Attributes & FANoUserView)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* hide internal navigation fields */
|
||||||
|
if (field.Attributes & FANavigation && !(field.Attributes & (FAConfig | FAState)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Value sval = Serialize(val);
|
||||||
|
resultAttrs->Set(field.Name, sval);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultAttrs;
|
||||||
|
}
|
||||||
|
|
|
@ -59,10 +59,16 @@ private:
|
||||||
void UpdateSubscriptionsTimerHandler(void);
|
void UpdateSubscriptionsTimerHandler(void);
|
||||||
void UpdateSubscriptions(void);
|
void UpdateSubscriptions(void);
|
||||||
|
|
||||||
/* config dump */
|
/* config & status dump */
|
||||||
void UpdateAllConfigObjects(void);
|
void UpdateAllConfigObjects(void);
|
||||||
void SendConfigUpdate(const ConfigObject::Ptr& object, const String& typeName);
|
void SendConfigUpdate(const ConfigObject::Ptr& object, const String& typeName);
|
||||||
void SendStatusUpdate(const ConfigObject::Ptr& object, const String& typeName);
|
void SendStatusUpdate(const ConfigObject::Ptr& object, const String& typeName);
|
||||||
|
|
||||||
|
/* utilities */
|
||||||
|
static String FormatCheckSumBinary(const String& str);
|
||||||
|
static String CalculateCheckSumString(const String& str);
|
||||||
|
static String CalculateCheckSumGroups(const Array::Ptr& groups);
|
||||||
|
static String CalculateCheckSumAttrs(const Dictionary::Ptr& attrs);
|
||||||
static Dictionary::Ptr SerializeObjectAttrs(const Object::Ptr& object, int fieldType);
|
static Dictionary::Ptr SerializeObjectAttrs(const Object::Ptr& object, int fieldType);
|
||||||
|
|
||||||
static void StateChangedHandler(const ConfigObject::Ptr& object);
|
static void StateChangedHandler(const ConfigObject::Ptr& object);
|
||||||
|
|
Loading…
Reference in New Issue