From 4851def51cd584c2bc911b83915be113e513f0c6 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Jan 2016 10:35:04 -0800 Subject: [PATCH] Add status HTTP server to AC Monitor --- assignment-client/src/AssignmentClientApp.cpp | 10 ++- assignment-client/src/AssignmentClientApp.h | 1 + .../src/AssignmentClientMonitor.cpp | 76 ++++++++++++++----- .../src/AssignmentClientMonitor.h | 19 ++++- assignment-client/src/octree/OctreeServer.cpp | 2 +- domain-server/src/DomainServer.cpp | 4 +- ice-server/src/IceServer.cpp | 2 +- .../embedded-webserver/src/HTTPManager.cpp | 5 +- .../embedded-webserver/src/HTTPManager.h | 3 +- .../embedded-webserver/src/HTTPSManager.cpp | 4 +- .../embedded-webserver/src/HTTPSManager.h | 11 +-- 11 files changed, 97 insertions(+), 40 deletions(-) diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index 9d5e8843d0..19a3350d0d 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -94,6 +94,9 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : const QCommandLineOption monitorPortOption(ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION, "assignment-client monitor port", "port"); 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"); parser.addOption(logDirectoryOption); @@ -135,6 +138,11 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : numForks = minForks; } + quint16 httpStatusPort { 0 }; + if (parser.isSet(httpStatusPortOption)) { + httpStatusPort = parser.value(httpStatusPortOption).toUShort(); + } + QDir logDirectory { "." }; if (parser.isSet(logDirectoryOption)) { logDirectory = parser.value(logDirectoryOption); @@ -212,7 +220,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : AssignmentClientMonitor* monitor = new AssignmentClientMonitor(numForks, minForks, maxForks, requestAssignmentType, assignmentPool, listenPort, walletUUID, assignmentServerHostname, - assignmentServerPort, logDirectory); + assignmentServerPort, httpStatusPort, logDirectory); monitor->setParent(this); connect(this, &QCoreApplication::aboutToQuit, monitor, &AssignmentClientMonitor::aboutToQuit); } else { diff --git a/assignment-client/src/AssignmentClientApp.h b/assignment-client/src/AssignmentClientApp.h index b99b442bbb..37d3b9cc1d 100644 --- a/assignment-client/src/AssignmentClientApp.h +++ b/assignment-client/src/AssignmentClientApp.h @@ -25,6 +25,7 @@ const QString ASSIGNMENT_NUM_FORKS_OPTION = "n"; const QString ASSIGNMENT_MIN_FORKS_OPTION = "min"; const QString ASSIGNMENT_MAX_FORKS_OPTION = "max"; 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"; class AssignmentClientApp : public QCoreApplication { diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index bb70c8464f..b9c34e9dd7 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -23,6 +23,7 @@ #include "AssignmentClientApp.h" #include "AssignmentClientChildData.h" #include "SharedUtil.h" +#include const QString ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME = "assignment-client-monitor"; const int WAIT_FOR_CHILD_MSECS = 1000; @@ -32,7 +33,8 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen const unsigned int maxAssignmentClientForks, Assignment::Type requestAssignmentType, QString assignmentPool, quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname, - quint16 assignmentServerPort, QDir logDirectory) : + quint16 assignmentServerPort, quint16 httpStatusServerPort, QDir logDirectory) : + _httpManager(QHostAddress::LocalHost, httpStatusServerPort, "", this), _numAssignmentClientForks(numAssignmentClientForks), _minAssignmentClientForks(minAssignmentClientForks), _maxAssignmentClientForks(maxAssignmentClientForks), @@ -84,24 +86,21 @@ void AssignmentClientMonitor::simultaneousWaitOnChildren(int waitMsecs) { } } -void AssignmentClientMonitor::childProcessFinished() { - QProcess* childProcess = qobject_cast(sender()); - qint64 processID = _childProcesses.key(childProcess); - - if (processID > 0) { - qDebug() << "Child process" << processID << "has finished. Removing from internal map."; - _childProcesses.remove(processID); +void AssignmentClientMonitor::childProcessFinished(qint64 pid) { + if (_childProcesses.remove(pid)) { + qDebug() << "Child process" << pid << "has finished. Removed from internal map."; } } void AssignmentClientMonitor::stopChildProcesses() { + qDebug() << "Stopping child processes"; auto nodeList = DependencyManager::get(); // ask child processes to terminate - foreach(QProcess* childProcess, _childProcesses) { - if (childProcess->processId() > 0) { - qDebug() << "Attempting to terminate child process" << childProcess->processId(); - childProcess->terminate(); + for (auto& ac : _childProcesses) { + if (ac.process->processId() > 0) { + qDebug() << "Attempting to terminate child process" << ac.process->processId(); + ac.process->terminate(); } } @@ -109,10 +108,10 @@ void AssignmentClientMonitor::stopChildProcesses() { if (_childProcesses.size() > 0) { // ask even more firmly - foreach(QProcess* childProcess, _childProcesses) { - if (childProcess->processId() > 0) { - qDebug() << "Attempting to kill child process" << childProcess->processId(); - childProcess->kill(); + for (auto& ac : _childProcesses) { + if (ac.process->processId() > 0) { + qDebug() << "Attempting to kill child process" << ac.process->processId(); + ac.process->kill(); } } @@ -191,24 +190,28 @@ void AssignmentClientMonitor::spawnChildClient() { qDebug() << "Renaming " << stdoutPathTemp << " to " << stdoutPath; if (!_logDirectory.rename(stdoutFilenameTemp, stdoutFilename)) { qDebug() << "Failed to rename " << stdoutFilenameTemp; + stdoutPath = stdoutPathTemp; stdoutFilename = stdoutFilenameTemp; } qDebug() << "Renaming " << stderrPathTemp << " to " << stderrPath; if (!QFile::rename(stderrPathTemp, stderrPath)) { qDebug() << "Failed to rename " << stderrFilenameTemp; + stderrPath = stderrPathTemp; stderrFilename = stderrFilenameTemp; } - qDebug() << "Child stdout being written to: " << stdoutPathTemp; - qDebug() << "Child stderr being written to: " << stderrPathTemp; + qDebug() << "Child stdout being written to: " << stdoutFilename; + qDebug() << "Child stderr being written to: " << stderrFilename; if (assignmentClient->processId() > 0) { + auto pid = assignmentClient->processId(); // 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(&QProcess::finished), + this, [this, pid]() { childProcessFinished(pid); }); 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(QSharedPointerreadPrimitive(&assignmentType); - childData->setChildType((Assignment::Type) assignmentType); + childData->setChildType(Assignment::Type(assignmentType)); // note when this child talked 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; +} diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index 27ef3e7cab..c7b552d470 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -21,24 +21,34 @@ #include #include "AssignmentClientChildData.h" +#include +#include 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 public: AssignmentClientMonitor(const unsigned int numAssignmentClientForks, const unsigned int minAssignmentClientForks, const unsigned int maxAssignmentClientForks, Assignment::Type requestAssignmentType, QString assignmentPool, quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname, - quint16 assignmentServerPort, QDir logDirectory); + quint16 assignmentServerPort, quint16 httpStatusServerPort, QDir logDirectory); ~AssignmentClientMonitor(); void stopChildProcesses(); private slots: void checkSpares(); - void childProcessFinished(); + void childProcessFinished(qint64 pid); void handleChildStatusPacket(QSharedPointer message); + bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false) override; + public slots: void aboutToQuit(); @@ -54,13 +64,14 @@ private: const unsigned int _minAssignmentClientForks; const unsigned int _maxAssignmentClientForks; + HTTPManager _httpManager; Assignment::Type _requestAssignmentType; QString _assignmentPool; QUuid _walletUUID; QString _assignmentServerHostname; quint16 _assignmentServerPort; - QMap _childProcesses; + QMap _childProcesses; }; #endif // hifi_AssignmentClientMonitor_h diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 410aa922dc..22bbed2a25 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -283,7 +283,7 @@ void OctreeServer::initHTTPManager(int port) { QString documentRoot = QString("%1/resources/web").arg(QCoreApplication::applicationDirPath()); // 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) { diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index e219b47571..614b90cb18 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -46,7 +46,7 @@ const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.io"; DomainServer::DomainServer(int argc, char* argv[]) : QCoreApplication(argc, argv), _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), _allAssignments(), _unfulfilledAssignments(), @@ -157,7 +157,7 @@ bool DomainServer::optionallyReadX509KeyAndCertificate() { QSslCertificate sslCertificate(&certFile); 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; diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index f65ff4a8cf..2baa7a13a7 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -27,7 +27,7 @@ IceServer::IceServer(int argc, char* argv[]) : _id(QUuid::createUuid()), _serverSocket(), _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 qDebug() << "ice-server socket is listening on" << ICE_SERVER_DEFAULT_PORT; diff --git a/libraries/embedded-webserver/src/HTTPManager.cpp b/libraries/embedded-webserver/src/HTTPManager.cpp index 4c804f2e7b..7cbdf01bbc 100644 --- a/libraries/embedded-webserver/src/HTTPManager.cpp +++ b/libraries/embedded-webserver/src/HTTPManager.cpp @@ -23,8 +23,9 @@ const int SOCKET_ERROR_EXIT_CODE = 2; 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), + _listenAddress(listenAddress), _documentRoot(documentRoot), _requestHandler(requestHandler), _port(port) @@ -178,7 +179,7 @@ void HTTPManager::isTcpServerListening() { bool HTTPManager::bindSocket() { 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(); return true; diff --git a/libraries/embedded-webserver/src/HTTPManager.h b/libraries/embedded-webserver/src/HTTPManager.h index 03498fbe8d..90a896ccf5 100644 --- a/libraries/embedded-webserver/src/HTTPManager.h +++ b/libraries/embedded-webserver/src/HTTPManager.h @@ -33,7 +33,7 @@ class HTTPManager : public QTcpServer, public HTTPRequestHandler { Q_OBJECT public: /// 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); @@ -49,6 +49,7 @@ protected: virtual void incomingConnection(qintptr socketDescriptor); virtual bool requestHandledByRequestHandler(HTTPConnection* connection, const QUrl& url); + QHostAddress _listenAddress; QString _documentRoot; HTTPRequestHandler* _requestHandler; QTimer* _isListeningTimer; diff --git a/libraries/embedded-webserver/src/HTTPSManager.cpp b/libraries/embedded-webserver/src/HTTPSManager.cpp index a745d7605e..ee61f15457 100644 --- a/libraries/embedded-webserver/src/HTTPSManager.cpp +++ b/libraries/embedded-webserver/src/HTTPSManager.cpp @@ -15,9 +15,9 @@ #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) : - HTTPManager(port, documentRoot, requestHandler, parent), + HTTPManager(listenAddress, port, documentRoot, requestHandler, parent), _certificate(certificate), _privateKey(privateKey), _sslRequestHandler(requestHandler) diff --git a/libraries/embedded-webserver/src/HTTPSManager.h b/libraries/embedded-webserver/src/HTTPSManager.h index 66c0c76d0b..2d3cc9ed62 100644 --- a/libraries/embedded-webserver/src/HTTPSManager.h +++ b/libraries/embedded-webserver/src/HTTPSManager.h @@ -26,7 +26,8 @@ public: class HTTPSManager : public HTTPManager, public HTTPSRequestHandler { Q_OBJECT public: - HTTPSManager(quint16 port, + HTTPSManager(QHostAddress listenAddress, + quint16 port, const QSslCertificate& certificate, const QSslKey& privateKey, const QString& documentRoot, @@ -35,12 +36,12 @@ public: void setCertificate(const QSslCertificate& certificate) { _certificate = certificate; } void setPrivateKey(const QSslKey& privateKey) { _privateKey = privateKey; } - bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false); - bool handleHTTPSRequest(HTTPSConnection* 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) override; protected: - void incomingConnection(qintptr socketDescriptor); - bool requestHandledByRequestHandler(HTTPConnection* connection, const QUrl& url); + void incomingConnection(qintptr socketDescriptor) override; + bool requestHandledByRequestHandler(HTTPConnection* connection, const QUrl& url) override; private: QSslCertificate _certificate; QSslKey _privateKey;