feat(server): admin port and interface (#709)

* feat(server): admin port and interface

Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
This commit is contained in:
Boaz Sade 2023-01-19 19:59:07 +02:00 committed by GitHub
parent 5af6ee9b27
commit 49e53d550e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 47 additions and 3 deletions

View file

@ -143,6 +143,9 @@ In addition, it has Dragonfly specific arguments options:
* `hz` - key expiry evaluation frequency. Default is 100. Lower frequency uses less cpu when * `hz` - key expiry evaluation frequency. Default is 100. Lower frequency uses less cpu when
idle at the expense of slower eviction rate. idle at the expense of slower eviction rate.
* `save_schedule` - glob spec for the UTC time to save a snapshot which matches HH:MM (24h time). default: "" * `save_schedule` - glob spec for the UTC time to save a snapshot which matches HH:MM (24h time). default: ""
* `primary_port_http_enabled` - If true allows accessing http console on main TCP port, default: true
* `admin_port` - If set, would enable admin access to console on the assigned port. This supports both HTTP and RESP protocols. default disabled
* `admin_bind` - If set, the admin consol TCP connection would be bind the given address. This supports both HTTP and RESP protocols. default any
### Example Start Script, with popular options: ### Example Start Script, with popular options:

View file

@ -25,7 +25,17 @@
ABSL_FLAG(bool, tcp_nodelay, false, ABSL_FLAG(bool, tcp_nodelay, false,
"Configures dragonfly connections with socket option TCP_NODELAY"); "Configures dragonfly connections with socket option TCP_NODELAY");
ABSL_FLAG(bool, http_admin_console, true, "If true allows accessing http console on main TCP port"); ABSL_FLAG(bool, primary_port_http_enabled, true,
"If true allows accessing http console on main TCP port");
ABSL_FLAG(
std::uint16_t, admin_port, 0,
"If set, would enable admin access to console on the assigned port. This supports both HTTP "
"and RESP protocols");
ABSL_FLAG(std::string, admin_bind, "",
"If set, the admin consol TCP connection would be bind the given address. "
"This supports both HTTP and RESP "
"protocols");
using namespace util; using namespace util;
using namespace std; using namespace std;
@ -326,8 +336,8 @@ void Connection::HandleRequests() {
#endif #endif
io::Result<bool> http_res{false}; io::Result<bool> http_res{false};
if (absl::GetFlag(FLAGS_http_admin_console))
http_res = CheckForHttpProto(peer); http_res = CheckForHttpProto(peer);
if (http_res) { if (http_res) {
if (*http_res) { if (*http_res) {
@ -404,6 +414,16 @@ uint32 Connection::GetClientId() const {
} }
io::Result<bool> Connection::CheckForHttpProto(FiberSocketBase* peer) { io::Result<bool> Connection::CheckForHttpProto(FiberSocketBase* peer) {
bool enabled = absl::GetFlag(FLAGS_primary_port_http_enabled);
if (!enabled) {
uint16_t admin_port = absl::GetFlag(FLAGS_admin_port);
// check if this connection is from the admin port, if so, override primary_port_http_enabled
LinuxSocketBase* lsb = static_cast<LinuxSocketBase*>(socket_.get());
enabled = lsb->LocalEndpoint().port() == admin_port;
}
if (!enabled) {
return false;
}
size_t last_len = 0; size_t last_len = 0;
do { do {
auto buf = io_buf_.AppendBuffer(); auto buf = io_buf_.AppendBuffer();

View file

@ -72,6 +72,8 @@ std::string AbslUnparseFlag(const MaxMemoryFlag& flag) {
ABSL_DECLARE_FLAG(uint32_t, port); ABSL_DECLARE_FLAG(uint32_t, port);
ABSL_DECLARE_FLAG(uint32_t, dbnum); ABSL_DECLARE_FLAG(uint32_t, dbnum);
ABSL_DECLARE_FLAG(uint32_t, memcache_port); ABSL_DECLARE_FLAG(uint32_t, memcache_port);
ABSL_DECLARE_FLAG(uint16_t, admin_port);
ABSL_DECLARE_FLAG(std::string, admin_bind);
ABSL_FLAG(bool, use_large_pages, false, "If true - uses large memory pages for allocations"); ABSL_FLAG(bool, use_large_pages, false, "If true - uses large memory pages for allocations");
ABSL_FLAG(string, bind, "", ABSL_FLAG(string, bind, "",
@ -319,6 +321,25 @@ bool RunEngine(ProactorPool* pool, AcceptServer* acceptor) {
} }
} }
std::uint16_t admin_port = GetFlag(FLAGS_admin_port);
if (admin_port != 0) {
const std::string& admin_bind = GetFlag(FLAGS_admin_bind);
// Note passing the result of c_str() for empty string in optimized mode don't work, we must
// explicitly set this to null in this case
const char* interface_addr = admin_bind.empty() ? nullptr : admin_bind.c_str();
const std::string printable_addr =
absl::StrCat("admin socket ", interface_addr ? interface_addr : "any", ":", admin_port);
Listener* admin_listener = new Listener{Protocol::REDIS, &service};
error_code ec = acceptor->AddListener(interface_addr, admin_port, admin_listener);
if (ec) {
LOG(ERROR) << "Failed to open " << printable_addr << ", error: " << ec.message();
delete admin_listener;
} else {
LOG(INFO) << "Listening on " << printable_addr;
}
}
error_code ec = acceptor->AddListener(bind_addr, port, main_listener); error_code ec = acceptor->AddListener(bind_addr, port, main_listener);
if (ec) { if (ec) {