Generalized Util::Config::is_restarting for rolling restarts, added rolling restart support to listening socket outputs

This commit is contained in:
Thulinma 2019-05-23 13:28:30 +02:00
parent 42da518d5f
commit ea443945fe
10 changed files with 72 additions and 24 deletions

View file

@ -35,6 +35,7 @@
#include <unistd.h> #include <unistd.h>
bool Util::Config::is_active = false; bool Util::Config::is_active = false;
bool Util::Config::is_restarting = false;
static Socket::Server *serv_sock_pointer = 0; static Socket::Server *serv_sock_pointer = 0;
uint32_t Util::Config::printDebugLevel = DEBUG; // uint32_t Util::Config::printDebugLevel = DEBUG; //
std::string Util::Config::streamName; std::string Util::Config::streamName;
@ -321,16 +322,19 @@ int Util::Config::forkServer(Socket::Server &server_socket, int (*callback)(Sock
} }
} }
Util::Procs::socketList.erase(server_socket.getSocket()); Util::Procs::socketList.erase(server_socket.getSocket());
server_socket.close(); if (!is_restarting){
server_socket.close();
}
return 0; return 0;
} }
int Util::Config::serveThreadedSocket(int (*callback)(Socket::Connection &)){ int Util::Config::serveThreadedSocket(int (*callback)(Socket::Connection &)){
Socket::Server server_socket; Socket::Server server_socket;
if (vals.isMember("socket")){ if (Socket::checkTrueSocket(0)){
server_socket = Socket::Server(0);
}else if (vals.isMember("socket")){
server_socket = Socket::Server(Util::getTmpFolder() + getString("socket")); server_socket = Socket::Server(Util::getTmpFolder() + getString("socket"));
} } else if (vals.isMember("port") && vals.isMember("interface")){
if (vals.isMember("port") && vals.isMember("interface")){
server_socket = Socket::Server(getInteger("port"), getString("interface"), false); server_socket = Socket::Server(getInteger("port"), getString("interface"), false);
} }
if (!server_socket.connected()){ if (!server_socket.connected()){
@ -340,6 +344,13 @@ int Util::Config::serveThreadedSocket(int (*callback)(Socket::Connection &)){
serv_sock_pointer = &server_socket; serv_sock_pointer = &server_socket;
DEVEL_MSG("Activating threaded server: %s", getString("cmd").c_str()); DEVEL_MSG("Activating threaded server: %s", getString("cmd").c_str());
activate(); activate();
if (server_socket.getSocket()){
int oldSock = server_socket.getSocket();
if (!dup2(oldSock, 0)){
server_socket = Socket::Server(0);
close(oldSock);
}
}
int r = threadServer(server_socket, callback); int r = threadServer(server_socket, callback);
serv_sock_pointer = 0; serv_sock_pointer = 0;
return r; return r;
@ -347,10 +358,11 @@ int Util::Config::serveThreadedSocket(int (*callback)(Socket::Connection &)){
int Util::Config::serveForkedSocket(int (*callback)(Socket::Connection &S)){ int Util::Config::serveForkedSocket(int (*callback)(Socket::Connection &S)){
Socket::Server server_socket; Socket::Server server_socket;
if (vals.isMember("socket")){ if (Socket::checkTrueSocket(0)){
server_socket = Socket::Server(0);
}else if (vals.isMember("socket")){
server_socket = Socket::Server(Util::getTmpFolder() + getString("socket")); server_socket = Socket::Server(Util::getTmpFolder() + getString("socket"));
} } else if (vals.isMember("port") && vals.isMember("interface")){
if (vals.isMember("port") && vals.isMember("interface")){
server_socket = Socket::Server(getInteger("port"), getString("interface"), false); server_socket = Socket::Server(getInteger("port"), getString("interface"), false);
} }
if (!server_socket.connected()){ if (!server_socket.connected()){
@ -360,6 +372,13 @@ int Util::Config::serveForkedSocket(int (*callback)(Socket::Connection &S)){
serv_sock_pointer = &server_socket; serv_sock_pointer = &server_socket;
DEVEL_MSG("Activating forked server: %s", getString("cmd").c_str()); DEVEL_MSG("Activating forked server: %s", getString("cmd").c_str());
activate(); activate();
if (server_socket.getSocket()){
int oldSock = server_socket.getSocket();
if (!dup2(oldSock, 0)){
server_socket = Socket::Server(0);
close(oldSock);
}
}
int r = forkServer(server_socket, callback); int r = forkServer(server_socket, callback);
serv_sock_pointer = 0; serv_sock_pointer = 0;
return r; return r;

View file

@ -24,6 +24,7 @@ namespace Util{
public: public:
// variables // variables
static bool is_active; ///< Set to true by activate(), set to false by the signal handler. static bool is_active; ///< Set to true by activate(), set to false by the signal handler.
static bool is_restarting; ///< Set to true when restarting, set to false on boot.
static uint32_t printDebugLevel; static uint32_t printDebugLevel;
static std::string streamName; ///< Used by debug messages to identify the stream name static std::string streamName; ///< Used by debug messages to identify the stream name
// functions // functions

View file

@ -58,6 +58,13 @@ bool Socket::isLocalhost(const std::string &remotehost){
return false; return false;
} }
///Checks if the given file descriptor is actually socket or not.
bool Socket::checkTrueSocket(int sock){
struct stat sBuf;
if (sock != -1 && !fstat(sock, &sBuf)){return S_ISSOCK(sBuf.st_mode);}
return false;
}
bool Socket::isLocal(const std::string &remotehost){ bool Socket::isLocal(const std::string &remotehost){
struct ifaddrs *ifAddrStruct = NULL; struct ifaddrs *ifAddrStruct = NULL;
struct ifaddrs *ifa = NULL; struct ifaddrs *ifa = NULL;
@ -400,9 +407,7 @@ void Socket::Connection::setBoundAddr(){
Socket::Connection::Connection(int sockNo){ Socket::Connection::Connection(int sockNo){
sSend = sockNo; sSend = sockNo;
sRecv = -1; sRecv = -1;
isTrueSocket = false; isTrueSocket = Socket::checkTrueSocket(sSend);
struct stat sBuf;
if (sSend != -1 && !fstat(sSend, &sBuf)){isTrueSocket = S_ISSOCK(sBuf.st_mode);}
setBoundAddr(); setBoundAddr();
up = 0; up = 0;
down = 0; down = 0;
@ -422,9 +427,7 @@ Socket::Connection::Connection(int write, int read){
}else{ }else{
sRecv = -1; sRecv = -1;
} }
isTrueSocket = false; isTrueSocket = Socket::checkTrueSocket(sSend);
struct stat sBuf;
if (sSend != -1 && !fstat(sSend, &sBuf)){isTrueSocket = S_ISSOCK(sBuf.st_mode);}
setBoundAddr(); setBoundAddr();
up = 0; up = 0;
down = 0; down = 0;
@ -1089,6 +1092,11 @@ Socket::Server::Server(){
sock = -1; sock = -1;
}// Socket::Server base Constructor }// Socket::Server base Constructor
/// Create a new Server from existing socket.
Socket::Server::Server(int fromSock){
sock = fromSock;
}
/// Create a new TCP Server. The socket is immediately bound and set to listen. /// Create a new TCP Server. The socket is immediately bound and set to listen.
/// A maximum of 100 connections will be accepted between accept() calls. /// A maximum of 100 connections will be accepted between accept() calls.
/// Any further connections coming in will be dropped. /// Any further connections coming in will be dropped.

View file

@ -41,6 +41,7 @@ namespace Socket{
bool isLocal(const std::string & host); bool isLocal(const std::string & host);
/// Returns true if given human-readable hostname is a local address. /// Returns true if given human-readable hostname is a local address.
bool isLocalhost(const std::string & host); bool isLocalhost(const std::string & host);
bool checkTrueSocket(int sock);
/// A buffer made out of std::string objects that can be efficiently read from and written to. /// A buffer made out of std::string objects that can be efficiently read from and written to.
class Buffer{ class Buffer{
@ -165,7 +166,8 @@ namespace Socket{
bool IPv4bind(int port, std::string hostname, bool nonblock); ///< Attempt to bind an IPv4 socket bool IPv4bind(int port, std::string hostname, bool nonblock); ///< Attempt to bind an IPv4 socket
public: public:
Server(); ///< Create a new base Server. Server(); ///< Create a new base Server.
Server(int port, std::string hostname = "0.0.0.0", bool nonblock = false); ///< Create a new TCP Server. Server(int existingSock); ///< Create a new Server from existing socket.
Server(int port, std::string hostname, bool nonblock = false); ///< Create a new TCP Server.
Server(std::string adres, bool nonblock = false); ///< Create a new Unix Server. Server(std::string adres, bool nonblock = false); ///< Create a new Unix Server.
Connection accept(bool nonblock = false); ///< Accept any waiting connections. Connection accept(bool nonblock = false); ///< Accept any waiting connections.
void setBlocking(bool blocking); ///< Set this socket to be blocking (true) or nonblocking (false). void setBlocking(bool blocking); ///< Set this socket to be blocking (true) or nonblocking (false).

View file

@ -78,7 +78,7 @@ void statusMonitor(void *np){
} }
Util::sleep(3000); // wait at least 3 seconds Util::sleep(3000); // wait at least 3 seconds
} }
if (Controller::restarting){ if (Util::Config::is_restarting){
Controller::prepareActiveConnectorsForReload(); Controller::prepareActiveConnectorsForReload();
}else{ }else{
Controller::prepareActiveConnectorsForShutdown(); Controller::prepareActiveConnectorsForShutdown();
@ -371,7 +371,7 @@ int main_loop(int argc, char **argv){
}else{ }else{
shutdown_reason = "socket problem (API port closed)"; shutdown_reason = "socket problem (API port closed)";
} }
if (Controller::restarting){shutdown_reason = "restart (on request)";} if (Util::Config::is_restarting){shutdown_reason = "restart (on request)";}
Controller::conf.is_active = false; Controller::conf.is_active = false;
Controller::Log("CONF", "Controller shutting down because of " + shutdown_reason); Controller::Log("CONF", "Controller shutting down because of " + shutdown_reason);
} }
@ -388,7 +388,7 @@ int main_loop(int argc, char **argv){
// give everything some time to print messages // give everything some time to print messages
Util::wait(100); Util::wait(100);
std::cout << "Killed all processes, wrote config to disk. Exiting." << std::endl; std::cout << "Killed all processes, wrote config to disk. Exiting." << std::endl;
if (Controller::restarting){return 42;} if (Util::Config::is_restarting){return 42;}
// close stderr to make the stderr reading thread exit // close stderr to make the stderr reading thread exit
close(STDERR_FILENO); close(STDERR_FILENO);
return 0; return 0;
@ -396,7 +396,7 @@ int main_loop(int argc, char **argv){
void handleUSR1(int signum, siginfo_t *sigInfo, void *ignore){ void handleUSR1(int signum, siginfo_t *sigInfo, void *ignore){
Controller::Log("CONF", "USR1 received - restarting controller"); Controller::Log("CONF", "USR1 received - restarting controller");
Controller::restarting = true; Util::Config::is_restarting = true;
raise(SIGINT); // trigger restart raise(SIGINT); // trigger restart
} }
@ -436,9 +436,9 @@ int main(int argc, char **argv){
// wait for the process to exit // wait for the process to exit
int status; int status;
while (waitpid(pid, &status, 0) != pid && errno == EINTR){ while (waitpid(pid, &status, 0) != pid && errno == EINTR){
if (Controller::restarting){ if (Util::Config::is_restarting){
Controller::conf.is_active = true; Controller::conf.is_active = true;
Controller::restarting = false; Util::Config::is_restarting = false;
kill(pid, SIGUSR1); kill(pid, SIGUSR1);
} }
if (!Controller::conf.is_active){ if (!Controller::conf.is_active){

View file

@ -56,11 +56,13 @@ namespace Controller {
IPC::sharedPage f("MstCnns", 4096, false, false); IPC::sharedPage f("MstCnns", 4096, false, false);
const Util::RelAccX A(f.mapped, false); const Util::RelAccX A(f.mapped, false);
if (A.isReady()){ if (A.isReady()){
INFO_MSG("Reloading existing connectors to complete rolling restart");
for (uint32_t i = 0; i < A.getRCount(); ++i){ for (uint32_t i = 0; i < A.getRCount(); ++i){
char * p = A.getPointer("cmd", i); char * p = A.getPointer("cmd", i);
if (p != 0 && p[0] != 0){ if (p != 0 && p[0] != 0){
currentConnectors[p] = A.getInt("pid", i); currentConnectors[p] = A.getInt("pid", i);
Util::Procs::remember(A.getInt("pid", i)); Util::Procs::remember(A.getInt("pid", i));
kill(A.getInt("pid", i), SIGUSR1);
} }
} }
} }

View file

@ -196,10 +196,10 @@ void Controller::SharedMemStats(void * config){
} }
statPointer = 0; statPointer = 0;
HIGH_MSG("Stopping stats thread"); HIGH_MSG("Stopping stats thread");
if (Controller::restarting){ if (Util::Config::is_restarting){
statServer.abandon(); statServer.abandon();
} }
Controller::deinitState(Controller::restarting); Controller::deinitState(Util::Config::is_restarting);
} }
/// Gets a complete list of all streams currently in active state, with optional prefix matching /// Gets a complete list of all streams currently in active state, with optional prefix matching

View file

@ -20,7 +20,6 @@ namespace Controller {
tthread::mutex logMutex; tthread::mutex logMutex;
uint64_t logCounter = 0; uint64_t logCounter = 0;
bool configChanged = false; bool configChanged = false;
bool restarting = false;
bool isTerminal = false; bool isTerminal = false;
bool isColorized = false; bool isColorized = false;
uint32_t maxLogsRecs = 0; uint32_t maxLogsRecs = 0;

View file

@ -11,7 +11,6 @@ namespace Controller {
extern tthread::mutex logMutex;///< Mutex for log thread. extern tthread::mutex logMutex;///< Mutex for log thread.
extern tthread::mutex configMutex;///< Mutex for server config access. extern tthread::mutex configMutex;///< Mutex for server config access.
extern bool configChanged; ///< Bool that indicates config must be written to SHM. extern bool configChanged; ///< Bool that indicates config must be written to SHM.
extern bool restarting;///< Signals if the controller is shutting down (false) or restarting (true).
extern bool isTerminal;///< True if connected to a terminal and not a log file. extern bool isTerminal;///< True if connected to a terminal and not a log file.
extern bool isColorized;///< True if we colorize the output extern bool isColorized;///< True if we colorize the output
extern uint64_t logCounter; ///<Count of logged messages since boot extern uint64_t logCounter; ///<Count of logged messages since boot

View file

@ -9,6 +9,12 @@ int spawnForked(Socket::Connection & S){
return tmp.run(); return tmp.run();
} }
void handleUSR1(int signum, siginfo_t *sigInfo, void *ignore){
HIGH_MSG("USR1 received - triggering rolling restart");
Util::Config::is_restarting = true;
Util::Config::is_active = false;
}
int main(int argc, char * argv[]) { int main(int argc, char * argv[]) {
Util::redirectLogsIfNeeded(); Util::redirectLogsIfNeeded();
Util::Config conf(argv[0]); Util::Config conf(argv[0]);
@ -21,7 +27,19 @@ int main(int argc, char * argv[]) {
} }
conf.activate(); conf.activate();
if (mistOut::listenMode()){ if (mistOut::listenMode()){
{
struct sigaction new_action;
new_action.sa_sigaction = handleUSR1;
sigemptyset(&new_action.sa_mask);
new_action.sa_flags = 0;
sigaction(SIGUSR1, &new_action, NULL);
}
mistOut::listener(conf, spawnForked); mistOut::listener(conf, spawnForked);
if (conf.is_restarting && Socket::checkTrueSocket(0)){
INFO_MSG("Reloading input while re-using server socket");
execvp(argv[0], argv);
FAIL_MSG("Error reloading: %s", strerror(errno));
}
}else{ }else{
Socket::Connection S(fileno(stdout),fileno(stdin) ); Socket::Connection S(fileno(stdout),fileno(stdin) );
mistOut tmp(S); mistOut tmp(S);