Make sure the system update check is done via a DISPATCHER process.

This prevent possible hangs in the main server thread from the health check, and also ensures that the system update check API call can now return a new "checkingforupdates" status.
This commit is contained in:
Ken Moore
2017-10-27 13:35:42 -04:00
parent 4247c3529a
commit ce53715265
6 changed files with 76 additions and 21 deletions

View File

@@ -182,6 +182,24 @@ QJsonObject Dispatcher::killJobs(QStringList ids){
return obj;
}
bool Dispatcher::isJobActive(QString ID){
//qDebug() << " - Is Job Active:" << ID;
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];
for(int j=0; j<list.length(); j++){
if(ID == list[j]->ID){
//qDebug() << " -- " << !list[j]->isDone();
return !(list[j]->isDone());
}
} //end loop over list
}
}
//qDebug() << " -- NO";
return false; //could not find process with this ID
}
void Dispatcher::start(QString queuefile){
//Setup connections here (in case it was moved to different thread after creation)
//connect(this, SIGNAL(mkprocs(Dispatcher::PROC_QUEUE, DProcess*)), this, SLOT(mkProcs(Dispatcher::PROC_QUEUE, DProcess*)) );
@@ -243,7 +261,7 @@ void Dispatcher::ProcFinished(QString ID, QJsonObject log){
//qDebug() << " - Got Proc Finished Signal:" << ID;
LogManager::log(LogManager::DISPATCH, log);
//First emit any subsystem-specific event, falling back on the raw log
QJsonObject ev = CreateDispatcherEventNotification(ID,log);
QJsonObject ev = CreateDispatcherEventNotification(ID,log, true);
if(!ev.isEmpty()){
emit DispatchEvent(ev);
}else{
@@ -254,7 +272,7 @@ void Dispatcher::ProcFinished(QString ID, QJsonObject log){
void Dispatcher::ProcUpdated(QString ID, QJsonObject log){
//See if this needs to generate an event
QJsonObject ev = CreateDispatcherEventNotification(ID,log);
QJsonObject ev = CreateDispatcherEventNotification(ID,log, false);
if(!ev.isEmpty()){
emit DispatchEvent(ev);
}

View File

@@ -63,6 +63,7 @@ public:
QJsonObject listJobs();
QJsonObject killJobs(QStringList ids);
bool isJobActive(QString ID); //returns true if a job with this ID is running/pending
public slots:
//Main start/stop
@@ -84,7 +85,7 @@ private:
//Simplification routine for setting up a process
DProcess* createProcess(QString ID, QStringList cmds, QString workdir = "");
QJsonObject CreateDispatcherEventNotification(QString, QJsonObject);
QJsonObject CreateDispatcherEventNotification(QString, QJsonObject, bool);
// Functions to do parsing out dispatcher queued tasks
// Please keep these sorted

View File

@@ -9,8 +9,11 @@
#include "globals-qt.h"
#include "EventWatcher.h"
#include "Dispatcher.h"
#include "library/sysadm-update.h"
QJsonObject Dispatcher::CreateDispatcherEventNotification(QString ID, QJsonObject log, bool full_log){
//NOTE: full_log = true when the process has finished. If it is false, the process is still running and you are probably getting an incremental update of the process log
QJsonObject Dispatcher::CreateDispatcherEventNotification(QString ID, QJsonObject log){
//key outputs - need to set these if an event is going to be sent out
QJsonObject args; //any arguments to send out
QString namesp, name; //the namespace/name of the subsystem used
@@ -26,7 +29,7 @@ QJsonObject Dispatcher::CreateDispatcherEventNotification(QString ID, QJsonObjec
//Add the generic process values
args.insert("state",log.value("state").toString());
args.insert("process_details", log); //full process log array here
//Now parse the notification based on the dispatch ID or current command
//NOTE: There might be a random string on the end of the ID (to accomodate similar process calls)
// == sysadm/iohyve ==
@@ -37,14 +40,18 @@ QJsonObject Dispatcher::CreateDispatcherEventNotification(QString ID, QJsonObjec
//Do some parsing of the log
parseIohyveFetchOutput(cLog,&args);
}
// == sysadm/update ==
}else if(ID.startsWith("sysadm_update")){
namesp = "sysadm"; name="update";
//No special parsing here: the pc-updatemanager output should be available as-is
args.insert("update_log",cLog);
if(ID.section("::",0,0)=="sysadm_update_runupdates"){
namesp = "sysadm"; name="update";
//No special parsing here: the pc-updatemanager output should be available as-is
args.insert("update_log",cLog);
}else if(full_log && ID.section("::",0,0)=="sysadm_update_checkupdates"){
//qDebug() << "Got update check process finished";
sysadm::Update::saveCheckUpdateLog(cLog); //save this for use later
}
// == sysadm/pkg ==
}else if(ID.startsWith("sysadm_pkg")){
namesp = "sysadm"; name="pkg";
@@ -56,7 +63,7 @@ QJsonObject Dispatcher::CreateDispatcherEventNotification(QString ID, QJsonObjec
bool hasupdates = !cLog.contains("Your packages are up to date.");
args.insert("updates_available", hasupdates ? "true" : "false");
}
}else if(ID.section("-",0,0)=="sysadm_pkg_audit" && isFinished){
QStringList info = cLog.split("\n");
QStringList vuln, effects;
@@ -71,9 +78,9 @@ QJsonObject Dispatcher::CreateDispatcherEventNotification(QString ID, QJsonObjec
args.insert("vulnerable_pkgs",QJsonArray::fromStringList(vuln));
args.insert("impacts_pkgs",QJsonArray::fromStringList(effects));
}
}
//Now assemble the output as needed
if(namesp.isEmpty() || name.isEmpty()){ return QJsonObject(); } //no event
args.insert("event_system",namesp+"/"+name);
@@ -93,3 +100,7 @@ void Dispatcher::parseIohyveFetchOutput(QString outputLog, QJsonObject *out){
break;
}
}
/*void Dispatcher::parseUpdateCheckOutput(QString outputLog, QJsonObject *out){
}*/

View File

@@ -368,6 +368,7 @@ void EventWatcher::CheckSystemState(){
//Next Check for Updates
QJsonObject updates = sysadm::Update::checkUpdates(true); //do the "fast" version of updates
//qDebug() << "Health check - got updates status:" << updates;
if(!updates.isEmpty()){
if(updates.value("status").toString()!="noupdates"){
int tmp = 2;
@@ -387,6 +388,8 @@ void EventWatcher::CheckSystemState(){
}
}
}
}else if(updates.value("status").toString()=="checkingforupdates"){
//do nothing more here - still checking for updates
}else if(updates.value("status").toString()!="updaterunning"){
//updates are available - see if the auto-update flag is set, and start the updates as needed
QJsonObject upset = sysadm::Update::readSettings();

View File

@@ -39,6 +39,11 @@ QJsonObject Update::checkUpdates(bool fast) {
if(!QFile::exists("/usr/local/bin/pc-updatemanager")){
return retObject;
}
//See if the check for updates is currently running - just return nothing at the moment for that
if(DISPATCHER->isJobActive("sysadm_update_checkupdates")){
retObject.insert("status", "checkingforupdates");
return retObject;
}
//Check if the system is waiting to reboot
if(QFile::exists(UP_RBFILE)){
retObject.insert("status","rebootrequired");
@@ -57,7 +62,7 @@ QJsonObject Update::checkUpdates(bool fast) {
return retObject;
}
}
//Get the list of deatils from the update checks (fast/full)
//Get the list of details from the update checks (fast/full)
QStringList output;
QDateTime cdt = QDateTime::currentDateTime();
QDateTime fdt = cdt.addDays(-1); //just enough to trip the checks below if needed
@@ -72,18 +77,23 @@ QJsonObject Update::checkUpdates(bool fast) {
//Note: The "fast" check will only be used if the last full check was less than 12 hours earlier.
//qDebug() << " - UseFast Re-read";
output = General::readTextFile(UP_UPFILE);
}else if(secs<600 ){
//Note: This will re-use the previous check if it was less than 10 minutes ago (prevent hammering servers from user checks)
//qDebug() << " - Use Fast Re-read (failsafe - less than 10 minute interval)";
}else if(secs<300 ){
//Note: This will re-use the previous check if it was less than 5 minutes ago (prevent hammering servers from user checks)
//qDebug() << " - Use Fast Re-read (failsafe - less than 5 minute interval)";
output = General::readTextFile(UP_UPFILE);
}else{
//qDebug() << " - Run full check";
General::RunCommand("pc-updatemanager syncconf"); //always resync the config file before starting an update check
QStringList cmds; cmds << "pc-updatemanager syncconf" << "pc-updatemanager pkgcheck";
DISPATCHER->queueProcess("sysadm_update_checkupdates", cmds );
retObject.insert("status", "checkingforupdates");
//qDebug() << " - Done starting check";
return retObject;
/*General::RunCommand("pc-updatemanager syncconf"); //always resync the config file before starting an update check
output.append( General::RunCommand("pc-updatemanager pkgcheck").split("\n") );
while(output.last().simplified()==""){ output.removeLast(); }
if(!output.last().contains("ERROR:")){ //make sure there was network access available first - otherwise let it try again soon
General::writeTextFile(UP_UPFILE, output); //save this check for later "fast" updates
}
}*/
}
//qDebug() << "pc-updatemanager checks:" << output;
@@ -139,6 +149,16 @@ QJsonObject Update::checkUpdates(bool fast) {
return retObject;
}
void Update::saveCheckUpdateLog(QString log){
QStringList output = log.split("\n");
qDebug() << "Got Check Update Log:" << log << output;
while(!output.isEmpty() && output.last().simplified().isEmpty()){ output.removeLast(); }
if(output.isEmpty()){ return; }
if(!output.last().contains("ERROR:")){ //make sure there was network access available first - otherwise let it try again soon
General::writeTextFile(UP_UPFILE, output); //save this check for later "fast" updates
}
}
// List available branches we can switch to
QJsonObject Update::listBranches() {
QJsonObject retObject;

View File

@@ -19,6 +19,8 @@ public:
static QDateTime rebootRequiredSince();
//Listing routines
static QJsonObject checkUpdates(bool fast = false);
static void saveCheckUpdateLog(QString); //Internal for Dispatcher process usage - do not expose to public API
static QJsonObject listBranches();
//Start/stop update routine
static QJsonObject startUpdate(QJsonObject);
@@ -31,7 +33,7 @@ public:
static QJsonObject readLog(QJsonObject);
};
}
#endif