Add status HTTP server to AC Monitor

This commit is contained in:
Ryan Huffman 2016-01-08 10:35:04 -08:00
parent d567c215bb
commit 4851def51c
11 changed files with 97 additions and 40 deletions

View file

@ -94,6 +94,9 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
const QCommandLineOption monitorPortOption(ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION, "assignment-client monitor port", "port"); const QCommandLineOption monitorPortOption(ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION, "assignment-client monitor port", "port");
parser.addOption(monitorPortOption); parser.addOption(monitorPortOption);
const QCommandLineOption httpStatusPortOption(ASSIGNMENT_HTTP_STATUS_PORT, "http status server port", "http-status-port");
parser.addOption(httpStatusPortOption);
const QCommandLineOption logDirectoryOption(ASSIGNMENT_LOG_DIRECTORY, "directory to store logs", "log-directory"); const QCommandLineOption logDirectoryOption(ASSIGNMENT_LOG_DIRECTORY, "directory to store logs", "log-directory");
parser.addOption(logDirectoryOption); parser.addOption(logDirectoryOption);
@ -135,6 +138,11 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
numForks = minForks; numForks = minForks;
} }
quint16 httpStatusPort { 0 };
if (parser.isSet(httpStatusPortOption)) {
httpStatusPort = parser.value(httpStatusPortOption).toUShort();
}
QDir logDirectory { "." }; QDir logDirectory { "." };
if (parser.isSet(logDirectoryOption)) { if (parser.isSet(logDirectoryOption)) {
logDirectory = parser.value(logDirectoryOption); logDirectory = parser.value(logDirectoryOption);
@ -212,7 +220,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
AssignmentClientMonitor* monitor = new AssignmentClientMonitor(numForks, minForks, maxForks, AssignmentClientMonitor* monitor = new AssignmentClientMonitor(numForks, minForks, maxForks,
requestAssignmentType, assignmentPool, requestAssignmentType, assignmentPool,
listenPort, walletUUID, assignmentServerHostname, listenPort, walletUUID, assignmentServerHostname,
assignmentServerPort, logDirectory); assignmentServerPort, httpStatusPort, logDirectory);
monitor->setParent(this); monitor->setParent(this);
connect(this, &QCoreApplication::aboutToQuit, monitor, &AssignmentClientMonitor::aboutToQuit); connect(this, &QCoreApplication::aboutToQuit, monitor, &AssignmentClientMonitor::aboutToQuit);
} else { } else {

View file

@ -25,6 +25,7 @@ const QString ASSIGNMENT_NUM_FORKS_OPTION = "n";
const QString ASSIGNMENT_MIN_FORKS_OPTION = "min"; const QString ASSIGNMENT_MIN_FORKS_OPTION = "min";
const QString ASSIGNMENT_MAX_FORKS_OPTION = "max"; const QString ASSIGNMENT_MAX_FORKS_OPTION = "max";
const QString ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION = "monitor-port"; const QString ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION = "monitor-port";
const QString ASSIGNMENT_HTTP_STATUS_PORT = "http-status-port";
const QString ASSIGNMENT_LOG_DIRECTORY = "log-directory"; const QString ASSIGNMENT_LOG_DIRECTORY = "log-directory";
class AssignmentClientApp : public QCoreApplication { class AssignmentClientApp : public QCoreApplication {

View file

@ -23,6 +23,7 @@
#include "AssignmentClientApp.h" #include "AssignmentClientApp.h"
#include "AssignmentClientChildData.h" #include "AssignmentClientChildData.h"
#include "SharedUtil.h" #include "SharedUtil.h"
#include <QtCore/QJsonDocument>
const QString ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME = "assignment-client-monitor"; const QString ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME = "assignment-client-monitor";
const int WAIT_FOR_CHILD_MSECS = 1000; const int WAIT_FOR_CHILD_MSECS = 1000;
@ -32,7 +33,8 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen
const unsigned int maxAssignmentClientForks, const unsigned int maxAssignmentClientForks,
Assignment::Type requestAssignmentType, QString assignmentPool, Assignment::Type requestAssignmentType, QString assignmentPool,
quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname, quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname,
quint16 assignmentServerPort, QDir logDirectory) : quint16 assignmentServerPort, quint16 httpStatusServerPort, QDir logDirectory) :
_httpManager(QHostAddress::LocalHost, httpStatusServerPort, "", this),
_numAssignmentClientForks(numAssignmentClientForks), _numAssignmentClientForks(numAssignmentClientForks),
_minAssignmentClientForks(minAssignmentClientForks), _minAssignmentClientForks(minAssignmentClientForks),
_maxAssignmentClientForks(maxAssignmentClientForks), _maxAssignmentClientForks(maxAssignmentClientForks),
@ -84,24 +86,21 @@ void AssignmentClientMonitor::simultaneousWaitOnChildren(int waitMsecs) {
} }
} }
void AssignmentClientMonitor::childProcessFinished() { void AssignmentClientMonitor::childProcessFinished(qint64 pid) {
QProcess* childProcess = qobject_cast<QProcess*>(sender()); if (_childProcesses.remove(pid)) {
qint64 processID = _childProcesses.key(childProcess); qDebug() << "Child process" << pid << "has finished. Removed from internal map.";
if (processID > 0) {
qDebug() << "Child process" << processID << "has finished. Removing from internal map.";
_childProcesses.remove(processID);
} }
} }
void AssignmentClientMonitor::stopChildProcesses() { void AssignmentClientMonitor::stopChildProcesses() {
qDebug() << "Stopping child processes";
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
// ask child processes to terminate // ask child processes to terminate
foreach(QProcess* childProcess, _childProcesses) { for (auto& ac : _childProcesses) {
if (childProcess->processId() > 0) { if (ac.process->processId() > 0) {
qDebug() << "Attempting to terminate child process" << childProcess->processId(); qDebug() << "Attempting to terminate child process" << ac.process->processId();
childProcess->terminate(); ac.process->terminate();
} }
} }
@ -109,10 +108,10 @@ void AssignmentClientMonitor::stopChildProcesses() {
if (_childProcesses.size() > 0) { if (_childProcesses.size() > 0) {
// ask even more firmly // ask even more firmly
foreach(QProcess* childProcess, _childProcesses) { for (auto& ac : _childProcesses) {
if (childProcess->processId() > 0) { if (ac.process->processId() > 0) {
qDebug() << "Attempting to kill child process" << childProcess->processId(); qDebug() << "Attempting to kill child process" << ac.process->processId();
childProcess->kill(); ac.process->kill();
} }
} }
@ -191,24 +190,28 @@ void AssignmentClientMonitor::spawnChildClient() {
qDebug() << "Renaming " << stdoutPathTemp << " to " << stdoutPath; qDebug() << "Renaming " << stdoutPathTemp << " to " << stdoutPath;
if (!_logDirectory.rename(stdoutFilenameTemp, stdoutFilename)) { if (!_logDirectory.rename(stdoutFilenameTemp, stdoutFilename)) {
qDebug() << "Failed to rename " << stdoutFilenameTemp; qDebug() << "Failed to rename " << stdoutFilenameTemp;
stdoutPath = stdoutPathTemp;
stdoutFilename = stdoutFilenameTemp; stdoutFilename = stdoutFilenameTemp;
} }
qDebug() << "Renaming " << stderrPathTemp << " to " << stderrPath; qDebug() << "Renaming " << stderrPathTemp << " to " << stderrPath;
if (!QFile::rename(stderrPathTemp, stderrPath)) { if (!QFile::rename(stderrPathTemp, stderrPath)) {
qDebug() << "Failed to rename " << stderrFilenameTemp; qDebug() << "Failed to rename " << stderrFilenameTemp;
stderrPath = stderrPathTemp;
stderrFilename = stderrFilenameTemp; stderrFilename = stderrFilenameTemp;
} }
qDebug() << "Child stdout being written to: " << stdoutPathTemp; qDebug() << "Child stdout being written to: " << stdoutFilename;
qDebug() << "Child stderr being written to: " << stderrPathTemp; qDebug() << "Child stderr being written to: " << stderrFilename;
if (assignmentClient->processId() > 0) { if (assignmentClient->processId() > 0) {
auto pid = assignmentClient->processId();
// make sure we hear that this process has finished when it does // make sure we hear that this process has finished when it does
connect(assignmentClient, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(childProcessFinished())); connect(assignmentClient, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
this, [this, pid]() { childProcessFinished(pid); });
qDebug() << "Spawned a child client with PID" << assignmentClient->processId(); qDebug() << "Spawned a child client with PID" << assignmentClient->processId();
_childProcesses.insert(assignmentClient->processId(), assignmentClient); _childProcesses.insert(assignmentClient->processId(), { assignmentClient, stdoutPath, stderrPath });
} }
} }
@ -296,9 +299,40 @@ void AssignmentClientMonitor::handleChildStatusPacket(QSharedPointer<ReceivedMes
quint8 assignmentType; quint8 assignmentType;
message->readPrimitive(&assignmentType); message->readPrimitive(&assignmentType);
childData->setChildType((Assignment::Type) assignmentType); childData->setChildType(Assignment::Type(assignmentType));
// note when this child talked // note when this child talked
matchingNode->setLastHeardMicrostamp(usecTimestampNow()); matchingNode->setLastHeardMicrostamp(usecTimestampNow());
} }
} }
bool AssignmentClientMonitor::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) {
if (url.path() == "/status") {
QByteArray response;
//QJsonDocument status;
QJsonObject status;
QJsonObject servers;
for (auto& ac : _childProcesses) {
QJsonObject server;
server["pid"] = ac.process->processId();
server["logStdout"] = ac.logStdoutPath;
server["logStderr"] = ac.logStderrPath;
servers[QString::number(ac.process->processId())] = server;
}
status["servers"] = servers;
QJsonDocument document { status };
connection->respond(HTTPConnection::StatusCode200, document.toJson());
} else {
connection->respond(HTTPConnection::StatusCode404);
}
return true;
}

View file

@ -21,24 +21,34 @@
#include <Assignment.h> #include <Assignment.h>
#include "AssignmentClientChildData.h" #include "AssignmentClientChildData.h"
#include <HTTPManager.h>
#include <HTTPConnection.h>
extern const char* NUM_FORKS_PARAMETER; extern const char* NUM_FORKS_PARAMETER;
class AssignmentClientMonitor : public QObject { struct ACProcess {
QProcess* process;
QString logStdoutPath;
QString logStderrPath;
};
class AssignmentClientMonitor : public QObject, public HTTPRequestHandler {
Q_OBJECT Q_OBJECT
public: public:
AssignmentClientMonitor(const unsigned int numAssignmentClientForks, const unsigned int minAssignmentClientForks, AssignmentClientMonitor(const unsigned int numAssignmentClientForks, const unsigned int minAssignmentClientForks,
const unsigned int maxAssignmentClientForks, Assignment::Type requestAssignmentType, const unsigned int maxAssignmentClientForks, Assignment::Type requestAssignmentType,
QString assignmentPool, quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname, QString assignmentPool, quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname,
quint16 assignmentServerPort, QDir logDirectory); quint16 assignmentServerPort, quint16 httpStatusServerPort, QDir logDirectory);
~AssignmentClientMonitor(); ~AssignmentClientMonitor();
void stopChildProcesses(); void stopChildProcesses();
private slots: private slots:
void checkSpares(); void checkSpares();
void childProcessFinished(); void childProcessFinished(qint64 pid);
void handleChildStatusPacket(QSharedPointer<ReceivedMessage> message); void handleChildStatusPacket(QSharedPointer<ReceivedMessage> message);
bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false) override;
public slots: public slots:
void aboutToQuit(); void aboutToQuit();
@ -54,13 +64,14 @@ private:
const unsigned int _minAssignmentClientForks; const unsigned int _minAssignmentClientForks;
const unsigned int _maxAssignmentClientForks; const unsigned int _maxAssignmentClientForks;
HTTPManager _httpManager;
Assignment::Type _requestAssignmentType; Assignment::Type _requestAssignmentType;
QString _assignmentPool; QString _assignmentPool;
QUuid _walletUUID; QUuid _walletUUID;
QString _assignmentServerHostname; QString _assignmentServerHostname;
quint16 _assignmentServerPort; quint16 _assignmentServerPort;
QMap<qint64, QProcess*> _childProcesses; QMap<qint64, ACProcess> _childProcesses;
}; };
#endif // hifi_AssignmentClientMonitor_h #endif // hifi_AssignmentClientMonitor_h

View file

@ -283,7 +283,7 @@ void OctreeServer::initHTTPManager(int port) {
QString documentRoot = QString("%1/resources/web").arg(QCoreApplication::applicationDirPath()); QString documentRoot = QString("%1/resources/web").arg(QCoreApplication::applicationDirPath());
// setup an httpManager with us as the request handler and the parent // setup an httpManager with us as the request handler and the parent
_httpManager = new HTTPManager(port, documentRoot, this, this); _httpManager = new HTTPManager(QHostAddress::AnyIPv4, port, documentRoot, this, this);
} }
bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) { bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) {

View file

@ -46,7 +46,7 @@ const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.io";
DomainServer::DomainServer(int argc, char* argv[]) : DomainServer::DomainServer(int argc, char* argv[]) :
QCoreApplication(argc, argv), QCoreApplication(argc, argv),
_gatekeeper(this), _gatekeeper(this),
_httpManager(DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this), _httpManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this),
_httpsManager(NULL), _httpsManager(NULL),
_allAssignments(), _allAssignments(),
_unfulfilledAssignments(), _unfulfilledAssignments(),
@ -157,7 +157,7 @@ bool DomainServer::optionallyReadX509KeyAndCertificate() {
QSslCertificate sslCertificate(&certFile); QSslCertificate sslCertificate(&certFile);
QSslKey privateKey(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, keyPassphraseString.toUtf8()); QSslKey privateKey(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, keyPassphraseString.toUtf8());
_httpsManager = new HTTPSManager(DOMAIN_SERVER_HTTPS_PORT, sslCertificate, privateKey, QString(), this, this); _httpsManager = new HTTPSManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTPS_PORT, sslCertificate, privateKey, QString(), this, this);
qDebug() << "TCP server listening for HTTPS connections on" << DOMAIN_SERVER_HTTPS_PORT; qDebug() << "TCP server listening for HTTPS connections on" << DOMAIN_SERVER_HTTPS_PORT;

View file

@ -27,7 +27,7 @@ IceServer::IceServer(int argc, char* argv[]) :
_id(QUuid::createUuid()), _id(QUuid::createUuid()),
_serverSocket(), _serverSocket(),
_activePeers(), _activePeers(),
_httpManager(ICE_SERVER_MONITORING_PORT, QString("%1/web/").arg(QCoreApplication::applicationDirPath()), this) _httpManager(QHostAddress::AnyIPv4, ICE_SERVER_MONITORING_PORT, QString("%1/web/").arg(QCoreApplication::applicationDirPath()), this)
{ {
// start the ice-server socket // start the ice-server socket
qDebug() << "ice-server socket is listening on" << ICE_SERVER_DEFAULT_PORT; qDebug() << "ice-server socket is listening on" << ICE_SERVER_DEFAULT_PORT;

View file

@ -23,8 +23,9 @@
const int SOCKET_ERROR_EXIT_CODE = 2; const int SOCKET_ERROR_EXIT_CODE = 2;
const int SOCKET_CHECK_INTERVAL_IN_MS = 30000; const int SOCKET_CHECK_INTERVAL_IN_MS = 30000;
HTTPManager::HTTPManager(quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler, QObject* parent) : HTTPManager::HTTPManager(const QHostAddress& listenAddress, quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler, QObject* parent) :
QTcpServer(parent), QTcpServer(parent),
_listenAddress(listenAddress),
_documentRoot(documentRoot), _documentRoot(documentRoot),
_requestHandler(requestHandler), _requestHandler(requestHandler),
_port(port) _port(port)
@ -178,7 +179,7 @@ void HTTPManager::isTcpServerListening() {
bool HTTPManager::bindSocket() { bool HTTPManager::bindSocket() {
qCDebug(embeddedwebserver) << "Attempting to bind TCP socket on port " << QString::number(_port); qCDebug(embeddedwebserver) << "Attempting to bind TCP socket on port " << QString::number(_port);
if (listen(QHostAddress::AnyIPv4, _port)) { if (listen(_listenAddress, _port)) {
qCDebug(embeddedwebserver) << "TCP socket is listening on" << serverAddress() << "and port" << serverPort(); qCDebug(embeddedwebserver) << "TCP socket is listening on" << serverAddress() << "and port" << serverPort();
return true; return true;

View file

@ -33,7 +33,7 @@ class HTTPManager : public QTcpServer, public HTTPRequestHandler {
Q_OBJECT Q_OBJECT
public: public:
/// Initializes the manager. /// Initializes the manager.
HTTPManager(quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler = NULL, QObject* parent = 0); HTTPManager(const QHostAddress& listenAddress, quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler = NULL, QObject* parent = 0);
bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false); bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false);
@ -49,6 +49,7 @@ protected:
virtual void incomingConnection(qintptr socketDescriptor); virtual void incomingConnection(qintptr socketDescriptor);
virtual bool requestHandledByRequestHandler(HTTPConnection* connection, const QUrl& url); virtual bool requestHandledByRequestHandler(HTTPConnection* connection, const QUrl& url);
QHostAddress _listenAddress;
QString _documentRoot; QString _documentRoot;
HTTPRequestHandler* _requestHandler; HTTPRequestHandler* _requestHandler;
QTimer* _isListeningTimer; QTimer* _isListeningTimer;

View file

@ -15,9 +15,9 @@
#include "HTTPSManager.h" #include "HTTPSManager.h"
HTTPSManager::HTTPSManager(quint16 port, const QSslCertificate& certificate, const QSslKey& privateKey, HTTPSManager::HTTPSManager(QHostAddress listenAddress, quint16 port, const QSslCertificate& certificate, const QSslKey& privateKey,
const QString& documentRoot, HTTPSRequestHandler* requestHandler, QObject* parent) : const QString& documentRoot, HTTPSRequestHandler* requestHandler, QObject* parent) :
HTTPManager(port, documentRoot, requestHandler, parent), HTTPManager(listenAddress, port, documentRoot, requestHandler, parent),
_certificate(certificate), _certificate(certificate),
_privateKey(privateKey), _privateKey(privateKey),
_sslRequestHandler(requestHandler) _sslRequestHandler(requestHandler)

View file

@ -26,7 +26,8 @@ public:
class HTTPSManager : public HTTPManager, public HTTPSRequestHandler { class HTTPSManager : public HTTPManager, public HTTPSRequestHandler {
Q_OBJECT Q_OBJECT
public: public:
HTTPSManager(quint16 port, HTTPSManager(QHostAddress listenAddress,
quint16 port,
const QSslCertificate& certificate, const QSslCertificate& certificate,
const QSslKey& privateKey, const QSslKey& privateKey,
const QString& documentRoot, const QString& documentRoot,
@ -35,12 +36,12 @@ public:
void setCertificate(const QSslCertificate& certificate) { _certificate = certificate; } void setCertificate(const QSslCertificate& certificate) { _certificate = certificate; }
void setPrivateKey(const QSslKey& privateKey) { _privateKey = privateKey; } void setPrivateKey(const QSslKey& privateKey) { _privateKey = privateKey; }
bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false); bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false) override;
bool handleHTTPSRequest(HTTPSConnection* connection, const QUrl& url, bool skipSubHandler = false); bool handleHTTPSRequest(HTTPSConnection* connection, const QUrl& url, bool skipSubHandler = false) override;
protected: protected:
void incomingConnection(qintptr socketDescriptor); void incomingConnection(qintptr socketDescriptor) override;
bool requestHandledByRequestHandler(HTTPConnection* connection, const QUrl& url); bool requestHandledByRequestHandler(HTTPConnection* connection, const QUrl& url) override;
private: private:
QSslCertificate _certificate; QSslCertificate _certificate;
QSslKey _privateKey; QSslKey _privateKey;