1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ 2 3 #ifndef APILISTENER_H 4 #define APILISTENER_H 5 6 #include "remote/apilistener-ti.hpp" 7 #include "remote/jsonrpcconnection.hpp" 8 #include "remote/httpserverconnection.hpp" 9 #include "remote/endpoint.hpp" 10 #include "remote/messageorigin.hpp" 11 #include "base/configobject.hpp" 12 #include "base/process.hpp" 13 #include "base/shared.hpp" 14 #include "base/timer.hpp" 15 #include "base/workqueue.hpp" 16 #include "base/tcpsocket.hpp" 17 #include "base/tlsstream.hpp" 18 #include "base/threadpool.hpp" 19 #include <atomic> 20 #include <boost/asio/io_context.hpp> 21 #include <boost/asio/ip/tcp.hpp> 22 #include <boost/asio/spawn.hpp> 23 #include <boost/asio/ssl/context.hpp> 24 #include <cstdint> 25 #include <mutex> 26 #include <set> 27 28 namespace icinga 29 { 30 31 class JsonRpcConnection; 32 33 /** 34 * @ingroup remote 35 */ 36 struct ConfigDirInformation 37 { 38 Dictionary::Ptr UpdateV1; 39 Dictionary::Ptr UpdateV2; 40 Dictionary::Ptr Checksums; 41 }; 42 43 /** 44 * If the version reported by icinga::Hello is not enough to tell whether 45 * the peer has a specific capability, add the latter to this bitmask. 46 * 47 * Note that due to the capability exchange via JSON-RPC and the state storage via JSON 48 * the bitmask numbers are stored in IEEE 754 64-bit floats. 49 * The latter have 53 digit bits which limit the bitmask. 50 * Not to run out of bits: 51 * 52 * Once all Icinga versions which don't have a specific capability are completely EOL, 53 * remove the respective capability checks and assume the peer has the capability. 54 * Once all Icinga versions which still check for the capability are completely EOL, 55 * remove the respective bit from icinga::Hello. 56 * Once all Icinga versions which still have the respective bit in icinga::Hello 57 * are completely EOL, remove the bit here. 58 * Once all Icinga versions which still have the respective bit here 59 * are completely EOL, feel free to re-use the bit. 60 * 61 * completely EOL = not supported, even if an important customer of us used it and 62 * not expected to appear in a multi-level cluster, e.g. a 4 level cluster with 63 * v2.11 -> v2.10 -> v2.9 -> v2.8 - v2.7 isn't here 64 * 65 * @ingroup remote 66 */ 67 enum class ApiCapabilities : uint_fast64_t 68 { 69 ExecuteArbitraryCommand = 1u 70 }; 71 72 /** 73 * @ingroup remote 74 */ 75 class ApiListener final : public ObjectImpl<ApiListener> 76 { 77 public: 78 DECLARE_OBJECT(ApiListener); 79 DECLARE_OBJECTNAME(ApiListener); 80 81 static boost::signals2::signal<void(bool)> OnMasterChanged; 82 83 ApiListener(); 84 85 static String GetApiDir(); 86 static String GetApiZonesDir(); 87 static String GetApiZonesStageDir(); 88 static String GetCertsDir(); 89 static String GetCaDir(); 90 static String GetCertificateRequestsDir(); 91 92 void UpdateSSLContext(); 93 94 static ApiListener::Ptr GetInstance(); 95 96 Endpoint::Ptr GetMaster() const; 97 bool IsMaster() const; 98 99 Endpoint::Ptr GetLocalEndpoint() const; 100 101 void SyncSendMessage(const Endpoint::Ptr& endpoint, const Dictionary::Ptr& message); 102 void RelayMessage(const MessageOrigin::Ptr& origin, const ConfigObject::Ptr& secobj, const Dictionary::Ptr& message, bool log); 103 104 static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata); 105 std::pair<Dictionary::Ptr, Dictionary::Ptr> GetStatus(); 106 107 bool AddAnonymousClient(const JsonRpcConnection::Ptr& aclient); 108 void RemoveAnonymousClient(const JsonRpcConnection::Ptr& aclient); 109 std::set<JsonRpcConnection::Ptr> GetAnonymousClients() const; 110 111 void AddHttpClient(const HttpServerConnection::Ptr& aclient); 112 void RemoveHttpClient(const HttpServerConnection::Ptr& aclient); 113 std::set<HttpServerConnection::Ptr> GetHttpClients() const; 114 115 static double CalculateZoneLag(const Endpoint::Ptr& endpoint); 116 117 /* filesync */ 118 static Value ConfigUpdateHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); 119 void HandleConfigUpdate(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); 120 121 /* configsync */ 122 static void ConfigUpdateObjectHandler(const ConfigObject::Ptr& object, const Value& cookie); 123 static Value ConfigUpdateObjectAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); 124 static Value ConfigDeleteObjectAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); 125 126 /* API config packages */ 127 void SetActivePackageStage(const String& package, const String& stage); 128 String GetActivePackageStage(const String& package); 129 void RemoveActivePackageStage(const String& package); 130 131 static Value HelloAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params); 132 133 static void UpdateObjectAuthority(); 134 135 static bool IsHACluster(); 136 static String GetFromZoneName(const Zone::Ptr& fromZone); 137 138 static String GetDefaultCertPath(); 139 static String GetDefaultKeyPath(); 140 static String GetDefaultCaPath(); 141 142 static inline UpdatedObjectAuthority()143 bool UpdatedObjectAuthority() 144 { 145 return m_UpdatedObjectAuthority.load(); 146 } 147 148 double GetTlsHandshakeTimeout() const override; 149 void SetTlsHandshakeTimeout(double value, bool suppress_events, const Value& cookie) override; 150 151 protected: 152 void OnConfigLoaded() override; 153 void OnAllConfigLoaded() override; 154 void Start(bool runtimeCreated) override; 155 void Stop(bool runtimeDeleted) override; 156 157 void ValidateTlsProtocolmin(const Lazy<String>& lvalue, const ValidationUtils& utils) override; 158 void ValidateTlsHandshakeTimeout(const Lazy<double>& lvalue, const ValidationUtils& utils) override; 159 160 private: 161 Shared<boost::asio::ssl::context>::Ptr m_SSLContext; 162 163 mutable std::mutex m_AnonymousClientsLock; 164 mutable std::mutex m_HttpClientsLock; 165 std::set<JsonRpcConnection::Ptr> m_AnonymousClients; 166 std::set<HttpServerConnection::Ptr> m_HttpClients; 167 168 Timer::Ptr m_Timer; 169 Timer::Ptr m_ReconnectTimer; 170 Timer::Ptr m_AuthorityTimer; 171 Timer::Ptr m_CleanupCertificateRequestsTimer; 172 Timer::Ptr m_ApiPackageIntegrityTimer; 173 174 Endpoint::Ptr m_LocalEndpoint; 175 176 static ApiListener::Ptr m_Instance; 177 static std::atomic<bool> m_UpdatedObjectAuthority; 178 179 void ApiTimerHandler(); 180 void ApiReconnectTimerHandler(); 181 void CleanupCertificateRequestsTimerHandler(); 182 void CheckApiPackageIntegrity(); 183 184 bool AddListener(const String& node, const String& service); 185 void AddConnection(const Endpoint::Ptr& endpoint); 186 187 void NewClientHandler( 188 boost::asio::yield_context yc, const Shared<boost::asio::io_context::strand>::Ptr& strand, 189 const Shared<AsioTlsStream>::Ptr& client, const String& hostname, ConnectionRole role 190 ); 191 void NewClientHandlerInternal( 192 boost::asio::yield_context yc, const Shared<boost::asio::io_context::strand>::Ptr& strand, 193 const Shared<AsioTlsStream>::Ptr& client, const String& hostname, ConnectionRole role 194 ); 195 void ListenerCoroutineProc(boost::asio::yield_context yc, const Shared<boost::asio::ip::tcp::acceptor>::Ptr& server, const Shared<boost::asio::ssl::context>::Ptr& sslContext); 196 197 WorkQueue m_RelayQueue; 198 WorkQueue m_SyncQueue{0, 4}; 199 200 std::mutex m_LogLock; 201 Stream::Ptr m_LogFile; 202 size_t m_LogMessageCount{0}; 203 204 bool RelayMessageOne(const Zone::Ptr& zone, const MessageOrigin::Ptr& origin, const Dictionary::Ptr& message, const Endpoint::Ptr& currentZoneMaster); 205 void SyncRelayMessage(const MessageOrigin::Ptr& origin, const ConfigObject::Ptr& secobj, const Dictionary::Ptr& message, bool log); 206 void PersistMessage(const Dictionary::Ptr& message, const ConfigObject::Ptr& secobj); 207 208 void OpenLogFile(); 209 void RotateLogFile(); 210 void CloseLogFile(); 211 static void LogGlobHandler(std::vector<int>& files, const String& file); 212 void ReplayLog(const JsonRpcConnection::Ptr& client); 213 214 static void CopyCertificateFile(const String& oldCertPath, const String& newCertPath); 215 216 void UpdateStatusFile(boost::asio::ip::tcp::endpoint localEndpoint); 217 void RemoveStatusFile(); 218 219 /* filesync */ 220 static std::mutex m_ConfigSyncStageLock; 221 222 void SyncLocalZoneDirs() const; 223 void SyncLocalZoneDir(const Zone::Ptr& zone) const; 224 225 void SendConfigUpdate(const JsonRpcConnection::Ptr& aclient); 226 227 static Dictionary::Ptr MergeConfigUpdate(const ConfigDirInformation& config); 228 229 static ConfigDirInformation LoadConfigDir(const String& dir); 230 static void ConfigGlobHandler(ConfigDirInformation& config, const String& path, const String& file); 231 232 static void TryActivateZonesStage(const std::vector<String>& relativePaths); 233 234 static String GetChecksum(const String& content); 235 static bool CheckConfigChange(const ConfigDirInformation& oldConfig, const ConfigDirInformation& newConfig); 236 237 void UpdateLastFailedZonesStageValidation(const String& log); 238 void ClearLastFailedZonesStageValidation(); 239 240 /* configsync */ 241 void UpdateConfigObject(const ConfigObject::Ptr& object, const MessageOrigin::Ptr& origin, 242 const JsonRpcConnection::Ptr& client = nullptr); 243 void DeleteConfigObject(const ConfigObject::Ptr& object, const MessageOrigin::Ptr& origin, 244 const JsonRpcConnection::Ptr& client = nullptr); 245 void SendRuntimeConfigObjects(const JsonRpcConnection::Ptr& aclient); 246 247 void SyncClient(const JsonRpcConnection::Ptr& aclient, const Endpoint::Ptr& endpoint, bool needSync); 248 249 /* API Config Packages */ 250 mutable std::mutex m_ActivePackageStagesLock; 251 std::map<String, String> m_ActivePackageStages; 252 253 void UpdateActivePackageStagesCache(); 254 }; 255 256 } 257 258 #endif /* APILISTENER_H */ 259