diff options
Diffstat (limited to 'configd/src/apps/sentinel')
-rw-r--r-- | configd/src/apps/sentinel/config-handler.cpp | 341 | ||||
-rw-r--r-- | configd/src/apps/sentinel/config-handler.h | 17 | ||||
-rw-r--r-- | configd/src/apps/sentinel/state-api.cpp | 27 | ||||
-rw-r--r-- | configd/src/apps/sentinel/state-api.h | 10 |
4 files changed, 14 insertions, 381 deletions
diff --git a/configd/src/apps/sentinel/config-handler.cpp b/configd/src/apps/sentinel/config-handler.cpp index d9f4d1f8bd7..a2ac35edd7f 100644 --- a/configd/src/apps/sentinel/config-handler.cpp +++ b/configd/src/apps/sentinel/config-handler.cpp @@ -14,20 +14,6 @@ LOG_SETUP(".config-handler"); namespace config::sentinel { -int -ConfigHandler::listen(int port) { - auto handle = vespalib::SocketAddress::select_local(port).listen(); - if (!handle) { - LOG(error, "Fatal: listen on command control socket failed: %s", strerror(errno)); - EV_STOPPING("config-sentinel", "listen on command control socket failed"); - exit(EXIT_FAILURE); - } - int fd = handle.release(); - fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); - fcntl(fd, F_SETFD, FD_CLOEXEC); - return fd; -} - void ConfigHandler::configure_port(int port) { @@ -43,21 +29,21 @@ ConfigHandler::configure_port(int port) EV_STOPPING("config-sentinel", "bad port"); exit(EXIT_FAILURE); } - LOG(debug, "Config-sentinel accepts connections on port %d", port); - close(_commandSocket); - _commandSocket = listen(port); - _boundPort = port; + if (port != _boundPort) { + LOG(debug, "Config-sentinel accepts connections on port %d", port); + _stateServer = std::make_unique<vespalib::StateServer>( + port, _stateApi.myHealth, _startMetrics.producer, _stateApi.myComponents); + _boundPort = port; + } } ConfigHandler::ConfigHandler() : _subscriber(), _services(), - _connections(), _outputConnections(), _boundPort(0), - _commandSocket(listen(0)), _startMetrics(), - _stateApi(_startMetrics.producer) + _stateApi() { _startMetrics.startedTime = time(nullptr); } @@ -65,17 +51,11 @@ ConfigHandler::ConfigHandler() ConfigHandler::~ConfigHandler() { terminateServices(false); - std::list<CommandConnection *>::iterator i; - for (i = _connections.begin(); i != _connections.end(); ++i) - { - delete *i; - } std::list<OutputConnection *>::iterator it; for (it = _outputConnections.begin(); it != _outputConnections.end(); ++it) { delete *it; } - close(_commandSocket); } void @@ -154,7 +134,6 @@ ConfigHandler::doConfigure() if (config.port.telnet != _boundPort) { configure_port(config.port.telnet); - _stateApi.bound(_boundPort); } if (!_rpcServer || config.port.rpc != _rpcServer->getPort()) { @@ -245,25 +224,6 @@ ConfigHandler::updateActiveFdset(fd_set *fds, int *maxNum) } } } - FD_SET(_commandSocket, fds); - if (_commandSocket >= *maxNum) { - *maxNum = _commandSocket + 1; - } - - std::list<CommandConnection *>::const_iterator - connections = _connections.begin(); - - while (connections != _connections.end()) { - CommandConnection *c = *connections; - ++connections; - int fd = c->fd(); - if (fd != -1) { - FD_SET(fd, fds); - if (fd >= *maxNum) { - *maxNum = fd + 1; - } - } - } } void @@ -292,47 +252,12 @@ ConfigHandler::handleOutputs() void ConfigHandler::handleCommands() { - { - // handle RPC commands - std::vector<Cmd::UP> got = _cmdQ.drain(); - for (const Cmd::UP & cmd : got) { - handleCmd(*cmd); - } - // implicit return via Cmd destructor - } - - // Accept new command connections, and read commands. - int fd; - struct sockaddr_storage sad; - socklen_t sadLen = sizeof(sad); - while ((fd = accept(_commandSocket, - reinterpret_cast<struct sockaddr *>(&sad), - &sadLen)) >= 0) - { - LOG(debug, "Got new command connection!"); - fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); - CommandConnection *c = new CommandConnection(fd); - _connections.push_back(c); - } - - std::list<CommandConnection *>::iterator dst; - std::list<CommandConnection *>::const_iterator src; - - src = _connections.begin(); - dst = _connections.begin(); - while (src != _connections.end()) { - CommandConnection *c = *src; - ++src; - handleCommand(c); - if (c->isFinished()) { - LOG(debug, "Connection is finished.."); - delete c; - } else { - *dst = c; - ++dst; - } + // handle RPC commands + std::vector<Cmd::UP> got = _cmdQ.drain(); + for (const Cmd::UP & cmd : got) { + handleCmd(*cmd); } - _connections.erase(dst, _connections.end()); + // implicit return via Cmd destructor } Service * @@ -359,23 +284,6 @@ ConfigHandler::serviceByName(const vespalib::string & name) void -splitCommand(char *line, char *&cmd, char *&args) -{ - cmd = line; - while (*line && !isspace(*line)) { - *line = tolower(*line); - ++line; - } - if (*line) { - *line++ = '\0'; - while (*line && isspace(*line)) { - ++line; - } - } - args = line; -} - -void ConfigHandler::handleCmd(const Cmd& cmd) { switch (cmd.type()) { @@ -449,234 +357,9 @@ ConfigHandler::handleCmd(const Cmd& cmd) } void -ConfigHandler::handleCommand(CommandConnection *c) -{ - while (char *line = c->getCommand()) { - LOG(debug, "Got command from connection: '%s'", line); - - char *cmd, *args; - splitCommand(line, cmd, args); - LOG(debug, "Command is '%s', args is '%s'", cmd, args); - if (strcmp(cmd, "ls") == 0) { - doLs(c, args); - } else if (strcmp(cmd, "get") == 0) { - doGet(c, args); - } else if (strcmp(cmd, "restart") == 0) { - doRestart(c, args); - } else if (strcmp(cmd, "forcerestart") == 0) { - doRestart(c, args, true); - } else if (strcmp(cmd, "start") == 0) { - doStart(c, args); - } else if (strcmp(cmd, "stop") == 0) { - doStop(c, args); - } else if (strcmp(cmd, "forcestop") == 0) { - doStop(c, args, true); - } else if (strcmp(cmd, "auto") == 0) { - doAuto(c, args); - } else if (strcmp(cmd, "manual") == 0) { - doManual(c, args); - } else if (strcmp(cmd, "quit") == 0) { - doQuit(c, args); - } else { - c->printf("ERROR: Unknown cmd '%s' " - "(ls/restart/start/stop/auto/manual/quit)\n", cmd); - } - } -} - -void ConfigHandler::updateMetrics() { _startMetrics.maybeLog(); } -void -ConfigHandler::doGet(CommandConnection *c, char *args) -{ - char *path, *extra; - splitCommand(args, path, extra); - if (path[0] == '/') { - updateMetrics(); - vespalib::string response = _stateApi.get(path); - if (response.size() > 0) { - c->printf("HTTP/1.0 200 OK\r\n" - "Content-Type: application/json; charset=ASCII\r\n\r\n"); - c->printf("%s", response.c_str()); - c->printf("\r\n"); - } else { - c->printf("HTTP/1.0 404 Not found\r\n" - "Content-Type: text/plain; charset=ASCII\r\n\r\n" - "This web server only has metrics\r\n"); - } - } else { - c->printf("HTTP/1.0 400 Bad URL\r\nContent-Type: text/plain; charset=ASCII\r\n\r\nThis web server only has metrics\r\n"); - } - c->finish(); - while (! c->isFinished()) { - c->getCommand(); - } -} - -void -ConfigHandler::doLs(CommandConnection *c, char *args) -{ - for (ServiceMap::iterator it(_services.begin()), mt(_services.end()); it != mt; it++) { - Service *service = it->second.get(); - if (*args && strcmp(args, service->name().c_str()) != 0) { - continue; - } - const SentinelConfig::Service& config = service->serviceConfig(); - c->printf("%s state=%s mode=%s pid=%d exitstatus=%d " - "autostart=%s autorestart=%s id=\"%s\"\n", - service->name().c_str(), service->stateName(), - service->isAutomatic() ? "AUTO" : "MANUAL", - service->pid(), service->exitStatus(), - config.autostart ? "TRUE" : "FALSE", - config.autorestart ? "TRUE" : "FALSE", - config.id.c_str()); - } - c->printf("\n"); -} - -void -ConfigHandler::doQuit(CommandConnection *c, char *) -{ - c->printf("Exiting.\n"); - c->finish(); -} - -void -ConfigHandler::doStart(CommandConnection *c, char *args) -{ - Service *service = serviceByName(args); - if (service == nullptr) { - c->printf("Cannot find any service named '%s'\n", args); - return; - } - - if (service->isRunning()) { - c->printf("ERROR: %s is already running as pid %d!\n", args, - service->pid()); - } else { - service->resetRestartPenalty(); - service->start(); - c->printf("%s started as pid %d, mode=%s\n", args, service->pid(), - service->isAutomatic() ? "AUTO" : "MANUAL"); - } -} - -void -ConfigHandler::doRestart(CommandConnection *c, char *args) -{ - doRestart(c, args, false); -} - -void -ConfigHandler::doRestart(CommandConnection *c, char *args, bool force) -{ - Service *service = serviceByName(args); - if (service == nullptr) { - c->printf("Cannot find any service named '%s'\n", args); - return; - } - - if (!service->isRunning()) { - service->resetRestartPenalty(); - service->start(); - c->printf("%s started as pid %d, mode=%s\n", args, service->pid(), - service->isAutomatic() ? "AUTO" : "MANUAL"); - return; - } - - if (!service->isAutomatic()) { - c->printf("ERROR: %s is in MANUAL mode, use stop+start\n", args); - return; - } - const SentinelConfig::Service& config = service->serviceConfig(); - if (!config.autorestart) { - c->printf("ERROR: %s does not autorestart, use stop+start\n", args); - return; - } - c->printf("terminating service %s pid %d, will be autorestarted\n", - args, service->pid()); - service->terminate(!force, false); -} - -void -ConfigHandler::doStop(CommandConnection *c, char *args) -{ - doStop(c, args, false); -} - -void -ConfigHandler::doStop(CommandConnection *c, char *args, bool force) -{ - Service *service = serviceByName(args); - if (service == nullptr) { - c->printf("Cannot find any service named '%s'\n", args); - return; - } - - if (!service->isRunning()) { - c->printf("%s is not running, it is in state %s. Cannot stop.\n", - service->name().c_str(), service->stateName()); - return; - } - const SentinelConfig::Service& config = service->serviceConfig(); - if (service->isAutomatic() && config.autorestart) { - c->printf("ERROR: %s in AUTO mode. Use restart, or manual+stop.\n", - args); - return; - } - c->printf("Stopping %s.\n", args); - service->terminate(!force, false); -} - -void -ConfigHandler::doAuto(CommandConnection *c, char *args) -{ - Service *service = serviceByName(args); - if (service == nullptr) { - c->printf("Cannot find any service named '%s'\n", args); - return; - } - - if (service->isAutomatic()) { - c->printf("%s is already automatic.\n", args); - } else { - service->setAutomatic(true); - const SentinelConfig::Service& config = service->serviceConfig(); - if (service->isRunning()) { - c->printf("%s is now automatic again (and running).\n", args); - } else if (config.autostart || config.autorestart) { - service->start(); - c->printf("%s is now automatic again (and started).\n", args); - } else { - c->printf("%s is now automatic again (but not started)\n", args); - } - } -} - - -void -ConfigHandler::doManual(CommandConnection *c, char *args) -{ - Service *service = serviceByName(args); - if (service == nullptr) { - c->printf("Cannot find any service named '%s'\n", args); - return; - } - - if (!service->isAutomatic()) { - c->printf("%s is already manual.\n", args); - } else { - service->setAutomatic(false); - if (service->isRunning()) { - c->printf("%s is now manual (but still running).\n", args); - } else { - c->printf("%s is now manual).\n", args); - } - } -} - } diff --git a/configd/src/apps/sentinel/config-handler.h b/configd/src/apps/sentinel/config-handler.h index e33bbf1c8da..a1ae054f888 100644 --- a/configd/src/apps/sentinel/config-handler.h +++ b/configd/src/apps/sentinel/config-handler.h @@ -8,6 +8,7 @@ #include "rpcserver.h" #include <vespa/config-sentinel.h> #include <vespa/config/config.h> +#include <vespa/vespalib/net/state_server.h> #include <sys/types.h> #include <sys/select.h> @@ -19,7 +20,6 @@ using config::ConfigHandle; namespace config::sentinel { -class CommandConnection; class OutputConnection; class ConfigHandler { @@ -29,14 +29,13 @@ private: ConfigSubscriber _subscriber; ConfigHandle<SentinelConfig>::UP _sentinelHandle; ServiceMap _services; - std::list<CommandConnection *> _connections; std::list<OutputConnection *> _outputConnections; CommandQueue _cmdQ; std::unique_ptr<RpcServer> _rpcServer; int _boundPort; - int _commandSocket; StartMetrics _startMetrics; StateApi _stateApi; + std::unique_ptr<vespalib::StateServer> _stateServer; ConfigHandler(const ConfigHandler&); ConfigHandler& operator =(const ConfigHandler&); @@ -44,7 +43,6 @@ private: Service *serviceByPid(pid_t pid); Service *serviceByName(const vespalib::string & name); void handleCommands(); - void handleCommand(CommandConnection *c); void handleCmd(const Cmd& cmd); void handleOutputs(); void handleChildDeaths(); @@ -54,17 +52,6 @@ private: void updateMetrics(); - void doGet(CommandConnection *c, char *args); - void doLs(CommandConnection *c, char *args); - void doRestart(CommandConnection *c, char *args); - void doRestart(CommandConnection *c, char *args, bool force); - void doStart(CommandConnection *c, char *args); - void doStop(CommandConnection *c, char *args); - void doStop(CommandConnection *c, char *args, bool force); - void doAuto(CommandConnection *c, char *args); - void doManual(CommandConnection *c, char *args); - void doQuit(CommandConnection *c, char *args); - void terminateServices(bool catchable, bool printDebug = false); void doConfigure(); diff --git a/configd/src/apps/sentinel/state-api.cpp b/configd/src/apps/sentinel/state-api.cpp index 56df10908f2..e63fee1863b 100644 --- a/configd/src/apps/sentinel/state-api.cpp +++ b/configd/src/apps/sentinel/state-api.cpp @@ -1,30 +1,3 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "state-api.h" -#include <vespa/vespalib/util/host_name.h> -#include <vespa/vespalib/util/stringfmt.h> - -namespace { - -std::map<vespalib::string, vespalib::string> noParams; - -} // namespace <unnamed> - - -namespace config { -namespace sentinel { - -vespalib::string -StateApi::get(const char *path) const -{ - return myStateApi.get(host_and_port, path, noParams); -} - -void -StateApi::bound(int port) -{ - host_and_port = vespalib::make_string("%s:%d", vespalib::HostName::get().c_str(), port); -} - -} // namespace config::sentinel -} // namespace config diff --git a/configd/src/apps/sentinel/state-api.h b/configd/src/apps/sentinel/state-api.h index ca080a35865..94c62209bec 100644 --- a/configd/src/apps/sentinel/state-api.h +++ b/configd/src/apps/sentinel/state-api.h @@ -2,7 +2,6 @@ #pragma once -#include <vespa/vespalib/net/state_api.h> #include <vespa/vespalib/net/simple_health_producer.h> #include <vespa/vespalib/net/simple_component_config_producer.h> #include <vespa/vespalib/metrics/simple_metrics.h> @@ -11,17 +10,8 @@ namespace config { namespace sentinel { struct StateApi { - vespalib::string host_and_port; vespalib::SimpleHealthProducer myHealth; vespalib::SimpleComponentConfigProducer myComponents; - vespalib::StateApi myStateApi; - - StateApi(vespalib::metrics::Producer &myMetrics) - : myStateApi(myHealth, myMetrics, myComponents) - {} - - vespalib::string get(const char *path) const; - void bound(int port); }; } // namespace config::sentinel |