Merge pull request #6511 from Icinga/feature/apilistener-dynamic-port

ApiListener: Add support for dynamic port handling
This commit is contained in:
Michael Friedrich 2018-08-09 12:09:23 +02:00 committed by GitHub
commit 3cc8bd2fcc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 104 additions and 28 deletions

View File

@ -37,6 +37,12 @@ has been removed and this setting has no effect.
> >
> This is important if you rely on the sysconfig configuration in your own scripts. > This is important if you rely on the sysconfig configuration in your own scripts.
### New Constants <a id="upgrading-to-2-10-path-new-constants"></a>
New [Icinga constants](17-language-reference.md#icinga-constants) have been added in this release.
* `ApiBindHost` and `ApiBindPort` to allow overriding the default ApiListener values. This will be used for an Icinga addon only.
## Upgrading to v2.9 <a id="upgrading-to-2-9"></a> ## Upgrading to v2.9 <a id="upgrading-to-2-9"></a>
### Deprecation and Removal Notes <a id="upgrading-to-2-9-deprecation-removal-notes"></a> ### Deprecation and Removal Notes <a id="upgrading-to-2-9-deprecation-removal-notes"></a>

View File

@ -409,8 +409,10 @@ Vars |**Read-write.** Contains a dictionary with global custom at
NodeName |**Read-write.** Contains the cluster node name. Set to the local hostname by default. NodeName |**Read-write.** Contains the cluster node name. Set to the local hostname by default.
RunAsUser |**Read-write.** Defines the user the Icinga 2 daemon is running as. Set in the Icinga 2 sysconfig. RunAsUser |**Read-write.** Defines the user the Icinga 2 daemon is running as. Set in the Icinga 2 sysconfig.
RunAsGroup |**Read-write.** Defines the group the Icinga 2 daemon is running as. Set in the Icinga 2 sysconfig. RunAsGroup |**Read-write.** Defines the group the Icinga 2 daemon is running as. Set in the Icinga 2 sysconfig.
MaxConcurrentChecks |**Read-write**. The number of max checks run simultaneously. Defaults to `512`. MaxConcurrentChecks |**Read-write.** The number of max checks run simultaneously. Defaults to `512`.
Environment |**Read-write**. The name of the Icinga environment. Included in the SNI host name when making outbound connections. Defaults to `production`. Environment |**Read-write.** The name of the Icinga environment. Included in the SNI host name when making outbound connections. Defaults to `production`.
ApiBindHost |**Read-write.** Overrides the default value for the ApiListener `bind_host` attribute. Not set by default.
ApiBindPort |**Read-write.** Overrides the default value for the ApiListener `bind_port` attribute. Not set by default.
Application runtime details: Application runtime details:

View File

@ -114,9 +114,21 @@ int Socket::GetError() const
/** /**
* Formats a sockaddr in a human-readable way. * Formats a sockaddr in a human-readable way.
* *
* @returns A String describing the sockaddr. * @returns A pair of host and service.
*/ */
String Socket::GetAddressFromSockaddr(sockaddr *address, socklen_t len) String Socket::GetHumanReadableAddress(const std::pair<String, String>& socketDetails)
{
std::ostringstream s;
s << "[" << socketDetails.first << "]:" << socketDetails.second;
return s.str();
}
/**
* Returns host and service as pair.
*
* @returns A pair with host and service.
*/
std::pair<String, String> Socket::GetDetailsFromSockaddr(sockaddr *address, socklen_t len)
{ {
char host[NI_MAXHOST]; char host[NI_MAXHOST];
char service[NI_MAXSERV]; char service[NI_MAXSERV];
@ -140,17 +152,15 @@ String Socket::GetAddressFromSockaddr(sockaddr *address, socklen_t len)
#endif /* _WIN32 */ #endif /* _WIN32 */
} }
std::ostringstream s; return std::make_pair(host, service);
s << "[" << host << "]:" << service;
return s.str();
} }
/** /**
* Returns a String describing the local address of the socket. * Returns a pair describing the local host and service of the socket.
* *
* @returns A String describing the local address. * @returns A pair describing the local host and service.
*/ */
String Socket::GetClientAddress() std::pair<String, String> Socket::GetClientAddressDetails()
{ {
boost::mutex::scoped_lock lock(m_SocketMutex); boost::mutex::scoped_lock lock(m_SocketMutex);
@ -175,22 +185,32 @@ String Socket::GetClientAddress()
#endif /* _WIN32 */ #endif /* _WIN32 */
} }
String address; std::pair<String, String> details;
try { try {
address = GetAddressFromSockaddr((sockaddr *)&sin, len); details = GetDetailsFromSockaddr((sockaddr *)&sin, len);
} catch (const std::exception&) { } catch (const std::exception&) {
/* already logged */ /* already logged */
} }
return address; return details;
} }
/** /**
* Returns a String describing the peer address of the socket. * Returns a String describing the local address of the socket.
* *
* @returns A String describing the peer address. * @returns A String describing the local address.
*/ */
String Socket::GetPeerAddress() String Socket::GetClientAddress()
{
return GetHumanReadableAddress(GetClientAddressDetails());
}
/**
* Returns a pair describing the peer host and service of the socket.
*
* @returns A pair describing the peer host and service.
*/
std::pair<String, String> Socket::GetPeerAddressDetails()
{ {
boost::mutex::scoped_lock lock(m_SocketMutex); boost::mutex::scoped_lock lock(m_SocketMutex);
@ -215,14 +235,24 @@ String Socket::GetPeerAddress()
#endif /* _WIN32 */ #endif /* _WIN32 */
} }
String address; std::pair<String, String> details;
try { try {
address = GetAddressFromSockaddr((sockaddr *)&sin, len); details = GetDetailsFromSockaddr((sockaddr *)&sin, len);
} catch (const std::exception&) { } catch (const std::exception&) {
/* already logged */ /* already logged */
} }
return address; return details;
}
/**
* Returns a String describing the peer address of the socket.
*
* @returns A String describing the peer address.
*/
String Socket::GetPeerAddress()
{
return GetHumanReadableAddress(GetPeerAddressDetails());
} }
/** /**
@ -415,4 +445,3 @@ void Socket::SocketPair(SOCKET s[2])
<< boost::errinfo_api_function("socketpair") << boost::errinfo_api_function("socketpair")
<< boost::errinfo_errno(errno)); << boost::errinfo_errno(errno));
} }

View File

@ -45,7 +45,9 @@ public:
void Close(); void Close();
std::pair<String, String> GetClientAddressDetails();
String GetClientAddress(); String GetClientAddress();
std::pair<String, String> GetPeerAddressDetails();
String GetPeerAddress(); String GetPeerAddress();
size_t Read(void *buffer, size_t size); size_t Read(void *buffer, size_t size);
@ -70,7 +72,8 @@ protected:
private: private:
SOCKET m_FD{INVALID_SOCKET}; /**< The socket descriptor. */ SOCKET m_FD{INVALID_SOCKET}; /**< The socket descriptor. */
static String GetAddressFromSockaddr(sockaddr *address, socklen_t len); static std::pair<String, String> GetDetailsFromSockaddr(sockaddr *address, socklen_t len);
static String GetHumanReadableAddress(const std::pair<String, String>& socketDetails);
}; };
class socket_error : virtual public std::exception, virtual public boost::exception { }; class socket_error : virtual public std::exception, virtual public boost::exception { };

View File

@ -264,8 +264,12 @@ void ApiListener::Stop(bool runtimeDeleted)
Log(LogInformation, "ApiListener") Log(LogInformation, "ApiListener")
<< "'" << GetName() << "' stopped."; << "'" << GetName() << "' stopped.";
boost::mutex::scoped_lock lock(m_LogLock); {
CloseLogFile(); boost::mutex::scoped_lock lock(m_LogLock);
CloseLogFile();
}
RemoveStatusFile();
} }
ApiListener::Ptr ApiListener::GetInstance() ApiListener::Ptr ApiListener::GetInstance()
@ -318,9 +322,6 @@ bool ApiListener::AddListener(const String& node, const String& service)
return false; return false;
} }
Log(LogInformation, "ApiListener")
<< "Adding new listener on port '" << service << "'";
TcpSocket::Ptr server = new TcpSocket(); TcpSocket::Ptr server = new TcpSocket();
try { try {
@ -331,11 +332,16 @@ bool ApiListener::AddListener(const String& node, const String& service)
return false; return false;
} }
Log(LogInformation, "ApiListener")
<< "Started new listener on '" << server->GetClientAddress() << "'";
std::thread thread(std::bind(&ApiListener::ListenerThreadProc, this, server)); std::thread thread(std::bind(&ApiListener::ListenerThreadProc, this, server));
thread.detach(); thread.detach();
m_Servers.insert(server); m_Servers.insert(server);
UpdateStatusFile(server);
return true; return true;
} }
@ -1469,3 +1475,28 @@ String ApiListener::GetFromZoneName(const Zone::Ptr& fromZone)
return fromZoneName; return fromZoneName;
} }
void ApiListener::UpdateStatusFile(TcpSocket::Ptr socket)
{
String path = Application::GetConst("CacheDir") + "/api-state.json";
std::pair<String, String> details = socket->GetClientAddressDetails();
Utility::SaveJsonFile(path, 0644, new Dictionary({
{"host", details.first},
{"port", details.second}
}));
}
void ApiListener::RemoveStatusFile()
{
String path = Application::GetConst("CacheDir") + "/api-state.json";
if (Utility::PathExists(path)) {
if (unlink(path.CStr()) < 0 && errno != ENOENT) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("unlink")
<< boost::errinfo_errno(errno)
<< boost::errinfo_file_name(path));
}
}
}

View File

@ -163,6 +163,9 @@ private:
static void CopyCertificateFile(const String& oldCertPath, const String& newCertPath); static void CopyCertificateFile(const String& oldCertPath, const String& newCertPath);
void UpdateStatusFile(TcpSocket::Ptr socket);
void RemoveStatusFile();
/* filesync */ /* filesync */
static ConfigDirInformation LoadConfigDir(const String& dir); static ConfigDirInformation LoadConfigDir(const String& dir);
static Dictionary::Ptr MergeConfigUpdate(const ConfigDirInformation& config); static Dictionary::Ptr MergeConfigUpdate(const ConfigDirInformation& config);

View File

@ -41,9 +41,11 @@ class ApiListener : ConfigObject
default {{{ return "TLSv1"; }}} default {{{ return "TLSv1"; }}}
}; };
[config] String bind_host; [config] String bind_host {
default {{{ return Application::GetConst("ApiBindHost"); }}}
};
[config] String bind_port { [config] String bind_port {
default {{{ return "5665"; }}} default {{{ return Application::GetConst("ApiBindPort", "5665"); }}}
}; };
[config] bool accept_config; [config] bool accept_config;