mirror of https://github.com/Icinga/icinga2.git
Merge pull request #1 from Al2Klimov/version
Introduce Endpoint#icinga_version
This commit is contained in:
commit
730075a177
|
@ -4,6 +4,8 @@
|
|||
#define ATOMIC_H
|
||||
|
||||
#include <atomic>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
@ -38,6 +40,80 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Wraps T into a std::atomic<T>-like interface.
|
||||
*
|
||||
* @ingroup base
|
||||
*/
|
||||
template<class T>
|
||||
class NotAtomic
|
||||
{
|
||||
public:
|
||||
inline T load() const
|
||||
{
|
||||
return m_Value;
|
||||
}
|
||||
|
||||
inline void store(T desired)
|
||||
{
|
||||
m_Value = std::move(desired);
|
||||
}
|
||||
|
||||
T m_Value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Tells whether to use std::atomic<T> or NotAtomic<T>.
|
||||
*
|
||||
* @ingroup base
|
||||
*/
|
||||
template<class T>
|
||||
struct Atomicable
|
||||
{
|
||||
// Doesn't work with too old compilers.
|
||||
//static constexpr bool value = std::is_trivially_copyable<T>::value && sizeof(T) <= sizeof(void*);
|
||||
static constexpr bool value = (std::is_fundamental<T>::value || std::is_pointer<T>::value) && sizeof(T) <= sizeof(void*);
|
||||
};
|
||||
|
||||
/**
|
||||
* Uses either std::atomic<T> or NotAtomic<T> depending on atomicable.
|
||||
*
|
||||
* @ingroup base
|
||||
*/
|
||||
template<bool atomicable>
|
||||
struct AtomicTemplate;
|
||||
|
||||
template<>
|
||||
struct AtomicTemplate<false>
|
||||
{
|
||||
template<class T>
|
||||
struct tmplt
|
||||
{
|
||||
typedef NotAtomic<T> type;
|
||||
};
|
||||
};
|
||||
|
||||
template<>
|
||||
struct AtomicTemplate<true>
|
||||
{
|
||||
template<class T>
|
||||
struct tmplt
|
||||
{
|
||||
typedef std::atomic<T> type;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Uses either std::atomic<T> or NotAtomic<T> depending on T.
|
||||
*
|
||||
* @ingroup base
|
||||
*/
|
||||
template<class T>
|
||||
struct EventuallyAtomic
|
||||
{
|
||||
typedef typename AtomicTemplate<Atomicable<T>::value>::template tmplt<T>::type type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* ATOMIC_H */
|
||||
|
|
|
@ -59,10 +59,10 @@ abstract class ConfigObject : ConfigObjectBase < ConfigType
|
|||
[config, no_user_modify] String __name (Name);
|
||||
[config, no_user_modify] String "name" (ShortName) {
|
||||
get {{{
|
||||
if (m_ShortName.IsEmpty())
|
||||
if (m_ShortName.m_Value.IsEmpty())
|
||||
return GetName();
|
||||
else
|
||||
return m_ShortName;
|
||||
return m_ShortName.m_Value;
|
||||
}}}
|
||||
};
|
||||
[config, no_user_modify] name(Zone) zone (ZoneName);
|
||||
|
|
|
@ -21,10 +21,10 @@ class Host : Checkable
|
|||
|
||||
[config] String display_name {
|
||||
get {{{
|
||||
if (m_DisplayName.IsEmpty())
|
||||
if (m_DisplayName.m_Value.IsEmpty())
|
||||
return GetName();
|
||||
else
|
||||
return m_DisplayName;
|
||||
return m_DisplayName.m_Value;
|
||||
}}}
|
||||
};
|
||||
|
||||
|
|
|
@ -11,10 +11,10 @@ class HostGroup : CustomVarObject
|
|||
{
|
||||
[config] String display_name {
|
||||
get {{{
|
||||
if (m_DisplayName.IsEmpty())
|
||||
if (m_DisplayName.m_Value.IsEmpty())
|
||||
return GetName();
|
||||
else
|
||||
return m_DisplayName;
|
||||
return m_DisplayName.m_Value;
|
||||
}}}
|
||||
};
|
||||
|
||||
|
|
|
@ -33,10 +33,10 @@ class Service : Checkable < ServiceNameComposer
|
|||
|
||||
[config] String display_name {
|
||||
get {{{
|
||||
if (m_DisplayName.IsEmpty())
|
||||
if (m_DisplayName.m_Value.IsEmpty())
|
||||
return GetShortName();
|
||||
else
|
||||
return m_DisplayName;
|
||||
return m_DisplayName.m_Value;
|
||||
}}}
|
||||
};
|
||||
[config, required] name(Host) host_name;
|
||||
|
|
|
@ -11,10 +11,10 @@ class ServiceGroup : CustomVarObject
|
|||
{
|
||||
[config] String display_name {
|
||||
get {{{
|
||||
if (m_DisplayName.IsEmpty())
|
||||
if (m_DisplayName.m_Value.IsEmpty())
|
||||
return GetName();
|
||||
else
|
||||
return m_DisplayName;
|
||||
return m_DisplayName.m_Value;
|
||||
}}}
|
||||
};
|
||||
|
||||
|
|
|
@ -12,10 +12,10 @@ class TimePeriod : CustomVarObject
|
|||
{
|
||||
[config] String display_name {
|
||||
get {{{
|
||||
if (m_DisplayName.IsEmpty())
|
||||
if (m_DisplayName.m_Value.IsEmpty())
|
||||
return GetName();
|
||||
else
|
||||
return m_DisplayName;
|
||||
return m_DisplayName.m_Value;
|
||||
}}}
|
||||
};
|
||||
[config] Dictionary::Ptr ranges;
|
||||
|
|
|
@ -13,10 +13,10 @@ class User : CustomVarObject
|
|||
{
|
||||
[config] String display_name {
|
||||
get {{{
|
||||
if (m_DisplayName.IsEmpty())
|
||||
if (m_DisplayName.m_Value.IsEmpty())
|
||||
return GetName();
|
||||
else
|
||||
return m_DisplayName;
|
||||
return m_DisplayName.m_Value;
|
||||
}}}
|
||||
};
|
||||
[config, no_user_modify, required] array(name(UserGroup)) groups {
|
||||
|
|
|
@ -11,10 +11,10 @@ class UserGroup : CustomVarObject
|
|||
{
|
||||
[config] String display_name {
|
||||
get {{{
|
||||
if (m_DisplayName.IsEmpty())
|
||||
if (m_DisplayName.m_Value.IsEmpty())
|
||||
return GetName();
|
||||
else
|
||||
return m_DisplayName;
|
||||
return m_DisplayName.m_Value;
|
||||
}}}
|
||||
};
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/asio/ssl/context.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_duration.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <climits>
|
||||
#include <cstdint>
|
||||
|
@ -506,6 +508,20 @@ void ApiListener::NewClientHandler(
|
|||
}
|
||||
}
|
||||
|
||||
static const auto l_AppVersionInt (([]() -> unsigned long {
|
||||
auto appVersion (Application::GetAppVersion());
|
||||
boost::regex rgx (R"EOF(^v?(\d+)\.(\d+)\.(\d+))EOF");
|
||||
boost::smatch match;
|
||||
|
||||
if (!boost::regex_search(appVersion.GetData(), match, rgx)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 100u * 100u * boost::lexical_cast<unsigned long>(match[1].str())
|
||||
+ 100u * boost::lexical_cast<unsigned long>(match[2].str())
|
||||
+ boost::lexical_cast<unsigned long>(match[3].str());
|
||||
})());
|
||||
|
||||
/**
|
||||
* Processes a new client connection.
|
||||
*
|
||||
|
@ -650,7 +666,9 @@ void ApiListener::NewClientHandlerInternal(
|
|||
JsonRpc::SendMessage(client, new Dictionary({
|
||||
{ "jsonrpc", "2.0" },
|
||||
{ "method", "icinga::Hello" },
|
||||
{ "params", new Dictionary() }
|
||||
{ "params", new Dictionary({
|
||||
{ "version", (double)l_AppVersionInt }
|
||||
}) }
|
||||
}), yc);
|
||||
|
||||
client->async_flush(yc);
|
||||
|
@ -683,6 +701,16 @@ void ApiListener::NewClientHandlerInternal(
|
|||
}
|
||||
|
||||
if (firstByte >= '0' && firstByte <= '9') {
|
||||
JsonRpc::SendMessage(client, new Dictionary({
|
||||
{ "jsonrpc", "2.0" },
|
||||
{ "method", "icinga::Hello" },
|
||||
{ "params", new Dictionary({
|
||||
{ "version", (double)l_AppVersionInt }
|
||||
}) }
|
||||
}), yc);
|
||||
|
||||
client->async_flush(yc);
|
||||
|
||||
ctype = ClientJsonRpc;
|
||||
} else {
|
||||
ctype = ClientHttp;
|
||||
|
@ -1607,6 +1635,18 @@ std::set<HttpServerConnection::Ptr> ApiListener::GetHttpClients() const
|
|||
|
||||
Value ApiListener::HelloAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params)
|
||||
{
|
||||
if (origin) {
|
||||
auto client (origin->FromClient);
|
||||
|
||||
if (client) {
|
||||
auto endpoint (client->GetEndpoint());
|
||||
|
||||
if (endpoint) {
|
||||
endpoint->SetIcingaVersion((double)params->Get("version"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Empty;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,9 @@ class Endpoint : ConfigObject
|
|||
|
||||
[state] Timestamp local_log_position;
|
||||
[state] Timestamp remote_log_position;
|
||||
[state] "unsigned long" icinga_version {
|
||||
default {{{ return 0; }}}
|
||||
};
|
||||
|
||||
[no_user_modify] bool connecting;
|
||||
[no_user_modify] bool syncing;
|
||||
|
|
|
@ -797,7 +797,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
|
|||
<< "{" << std::endl;
|
||||
|
||||
if (field.GetAccessor.empty() && !(field.Attributes & FANoStorage))
|
||||
m_Impl << "\t" << "return m_" << field.GetFriendlyName() << ";" << std::endl;
|
||||
m_Impl << "\t" << "return m_" << field.GetFriendlyName() << ".load();" << std::endl;
|
||||
else
|
||||
m_Impl << field.GetAccessor << std::endl;
|
||||
|
||||
|
@ -835,7 +835,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
|
|||
|
||||
|
||||
if (field.SetAccessor.empty() && !(field.Attributes & FANoStorage))
|
||||
m_Impl << "\t" << "m_" << field.GetFriendlyName() << " = value;" << std::endl;
|
||||
m_Impl << "\t" << "m_" << field.GetFriendlyName() << ".store(value);" << std::endl;
|
||||
else
|
||||
m_Impl << field.SetAccessor << std::endl << std::endl;
|
||||
|
||||
|
@ -1044,7 +1044,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
|
|||
if (field.Attributes & FANoStorage)
|
||||
continue;
|
||||
|
||||
m_Header << "\t" << field.Type.GetRealType() << " m_" << field.GetFriendlyName() << ";" << std::endl;
|
||||
m_Header << "\tEventuallyAtomic<" << field.Type.GetRealType() << ">::type m_" << field.GetFriendlyName() << ";" << std::endl;
|
||||
}
|
||||
|
||||
/* signal */
|
||||
|
@ -1431,6 +1431,7 @@ void ClassCompiler::CompileStream(const std::string& path, std::istream& input,
|
|||
<< "#include \"base/type.hpp\"" << std::endl
|
||||
<< "#include \"base/value.hpp\"" << std::endl
|
||||
<< "#include \"base/array.hpp\"" << std::endl
|
||||
<< "#include \"base/atomic.hpp\"" << std::endl
|
||||
<< "#include \"base/dictionary.hpp\"" << std::endl
|
||||
<< "#include <boost/signals2.hpp>" << std::endl << std::endl;
|
||||
|
||||
|
|
Loading…
Reference in New Issue