Commit my work in progress for the new Dispatcher subsystem. This is ~80% done right now (still filling out some of the internals - but the class framework is set in stone).

This commit is contained in:
Ken Moore
2016-01-26 12:55:08 -05:00
parent f8f8762616
commit 01124d2719
3 changed files with 231 additions and 0 deletions

137
src/server/Dispatcher.cpp Normal file
View File

@@ -0,0 +1,137 @@
// ===============================
// PC-BSD REST API Server
// Available under the 3-clause BSD License
// Written by: Ken Moore <ken@pcbsd.org> 2015-2016
// =================================
#include "Dispatcher.h"
#include "globals.h"
// ================================
// DProcess Class (Internal)
// ================================
DProcess::DProcess(QObject *parent) : QProcess(parent){
//Setup the process
this->setProcessEnvironment(QProcessEnvironment::systemEnvironment());
this->setProcessChannelMode(QProcess::MergedChannels);
//setup internal connections
connect(this, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(cmdFinished(int, QProcess::ExitStatus)) );
}
DProcess::~DProcess(){
if(this->state()!=QProcess::NotRunning)){
this->terminate();
}
}
void DProcess::startProc(){
if(cmds.isEmpty()){ emit ProcFinished(ID); return; }
QString cmd = cmds.takeFirst();
success = false; //not finished yet
if(!proclog.isEmpty()){ proclog.append("\n"); }
proclog.append("[Running Command: "+cmd+" ]");
this->start(cmd);
}
bool DProcess::isRunning(){
return (this->state()!=QProcess::NotRunning);
}
QString DProcess::getProcLog(){
//First update the internal log as needed
proclog.append( this->readAllStandardOutput() );
//Now return the current version of the log
return proclog;
}
void DProcess::cmdFinished(int ret, QProcess::ExitStatus status){
//determin success/failure
success = (status==QProcess::NormalExit && ret==0);
//update the log before starting another command
proclog.append( this->readAllStandardOutput() );
//Now run any additional commands
if(success){ startProc(); }//will emit the finished signal as needed if no more commands
else{
if(status==QProcess::NormalExit){
proclog.append("\n[Command Failed: " + QString::number(ret)+" ]");
}else{
proclog.append("\n[Command Failed: Process Crashed ]");
}
emit ProcFinished(ID);
}
}
// ================================
// Dispatcher Class
// ================================
Dispatcher::Dispatcher(){
}
Dispatcher::~Dispatcher(){
}
void Dispatcher::start(QString queuefile){
//load any previously-unrun processes
// TO DO
}
void Dispatcher::stop(){
//save any currently-unrun processes for next time the server starts
// TO DO
}
//Overloaded Main Calling Functions (single command, or multiple in-order commands)
void Dispatcher::queueProcess(QString ID, QString cmd){
queueProcess(NO_QUEUE, ID, QStringList() << cmd);
}
void Dispatcher::queueProcess(QString ID, QStringList cmds){
queueProcess(NO_QUEUE, ID, cmds);
}
void Dispatcher::queueProcess(Dispatcher::PROC_QUEUE queue, QString ID, QString cmd){
queueProcess(queue, ID, QStringList() << cmd);
}
void Dispatcher::queueProcess(Dispatcher::PROC_QUEUE queue, QString ID, QStringList cmds){
//This is the primary queueProcess() function - all the overloads end up here to do the actual work
DProcess *P = createProcess(ID, cmds);
QList<DProcess*> list;
if(!HASH.contains(queue)){ HASH.insert(queue, list); } //insert an empty list
HASH[queue] << P; //add this proc to the end of the list
if(queue==NO_QUEUE || HASH[queue].length()==1){ P->startProc(); } //go ahead and start it now
else{ CheckQueues(); }
}
// === PRIVATE ===
//Simplification routine for setting up a process
DProcess* Dispatcher:: createProcess(QString ID, QStringList cmds){
DProcess* P = new DProcess(this);
P->cmds = cmds;
P->ID = ID;
connect(P, SIGNAL(ProcFinished(QString)), this, SLOT(ProcFinished(QString)) );
return P;
}
// === PRIVATE SLOTS ===
void Dispatcher::ProcFinished(QString ID){
//Find the process with this ID and close it down (with proper events)
for int i=0; i<enum_length; i++){
PROC_QUEUE queue = static_cast(PROC_QUEUE>(i);
if(HASH.contains(queue)){
QList<DProcess*> list = HASH[queue];
bool found = false;
for(int l=0; l<list.length() && !found; l++){
if(list[l].ID==ID){
found = true;
}
} //end loop over queue list
}
}//end loop over queue enumeration
CheckQueues();
}
void Dispatcher::CheckQueues(){
}

88
src/server/Dispatcher.h Normal file
View File

@@ -0,0 +1,88 @@
// ===============================
// PC-BSD REST API Server
// Available under the 3-clause BSD License
// Written by: Ken Moore <ken@pcbsd.org> 2015-2016
// =================================
#ifndef _PCBSD_SYSADM_DISPATCH_PROCESS_SYSTEM_H
#define _PCBSD_SYSADM_DISPATCH_PROCESS_SYSTEM_H
#include "globals-qt.h"
// == Simple Process class for running sequential commands ==
// == INTERNAL ONLY - Do not use directly ==
class DProcess : public QProcess{
Q_OBJECT
public:
DProcess(QObject parent = 0);
~DProcess();
QString ID;
QStringList cmds;
bool success;
void startProc();
//Get the current process log (can be run during/after the process runs)
QString getProcLog();
bool isRunning();
private:
QString proclog;
private slots:
void cmdFinished(int, QProcess::ExitStatus);
signals:
void ProcFinished(QString ID);
};
class Dispatcher : public QObject{
Q_OBJECT
public:
enum PROC_QUEUE { NO_QUEUE = 0, PKG_QUEUE, IOCAGE_QUEUE };
#define enum_length 3 //This needs to be the number of items in the enum above
Dispatcher();
~Dispatcher();
public slots:
//Main start/stop
void start(QString queuefile); //load any previously-unrun processes
void stop(); //save any currently-unrun processes for next time
//Main Calling Functions (single command, or multiple in-order commands)
void queueProcess(QString ID, QString cmd); //uses NO_QUEUE
void queueProcess(QString ID, QStringList cmds); //uses NO_QUEUE
void queueProcess(Dispatcher::PROC_QUEUE, QString ID, QString cmd);
void queueProcess(Dispatcher::PROC_QUEUE, QString ID, QStringList cmds);
private:
// Queue file
QString queue_file;
//Internal lists
QHash<PROC_QUEUE, QList<DProcess*> > QUEUES;
//Simplification routine for setting up a process
DProcess* createProcess(QString ID, QStringList cmds){
DProcess* P = new DProcess(this);
P->cmds = cmds;
P->ID = ID;
connect(P, SIGNAL(ProcFinished(QString)), this, SLOT(ProcFinished(QString)) );
return P;
}
private slots:
void ProcFinished(QString ID);
void CheckQueues();
signals:
void DispatchFinished(QString ID, bool success);
void DispatchStarting(QString ID);
};
#endif

View File

@@ -22,6 +22,8 @@
#include <QDateTime>
#include <QTextStream>
#include <QProcess>
#include <QProcessEnvironment>
#include <QSslKey>
#include <QSslCertificate>
#include <QSslError>
@@ -46,10 +48,14 @@
#include <QDebug>
#include <QtDebug>
// SSL Version/File defines
#define SSLVERSION QSsl::TlsV1_0
#define SSLCERTFILE "/usr/local/etc/sysadm/restserver.crt"
#define SSLKEYFILE "/usr/local/etc/sysadm/restserver.key"
// Server Settings defines
#define DISPATCH_QUEUE "/usr/local/etc/sysadm/dispatch_queue"
inline QString DisplayPriority(int pri){
//ensure bounds
if(pri<0){ pri = 0; }