Example #1
0
void LPWatcher::checkPoolStatus(){
  //Now check zpool status for bad/running statuses
  QStringList zstat = getCmdOutput("zpool status");
    //parse the output
    QString pool, state, timestamp;
    QStringList cDev, cStat, cMsg, cSummary;
    //qDebug() << "-----zpool status------\n" << zstat.join("\n");
    bool newresilver = false; bool newscrub = false; bool newerror = false;
    for(int i=0; i<zstat.length(); i++){
      zstat[i] = zstat[i].simplified();
      if(zstat[i].isEmpty()){ continue; }
      //qDebug() << zstat[i];
      if(zstat[i].startsWith("pool:")){ pool = zstat[i].section(":",1,10).simplified(); }
      else if(zstat[i].startsWith("state:")){ state = zstat[i].section(":",1,10).simplified(); }
      else if(zstat[i].startsWith("scan:")){
	//check for scrubs/resilvering progress
	// ------ SCRUB ------
	if(zstat[i].contains("scrub")){
	  if(zstat[i].contains(" scrub repaired ")){
	    //Scrub Finished
	    zstat[i]  = zstat[i].replace("\t"," ").simplified();
	    timestamp = zstat[i].section(" ",10,14,QString::SectionSkipEmpty);
	    QString numFixed = zstat[i].section(" ",3,3,QString::SectionSkipEmpty);
	    QString numErr = zstat[i].section(" ",7,7,QString::SectionSkipEmpty);
	    QString timeRun = zstat[i].section(" ",5,5,QString::SectionSkipEmpty);
	    //Scrub finished previously
	    if(numFixed.toInt() > 0){ 
	      if(LOGS.value(60)!="ERROR"){ newscrub=true; }
	      LOGS.insert(60, "ERROR"); 
	      LOGS.insert(62, QString(tr("Scrub repaired %1 bad blocks")).arg(numFixed) );
	      LOGS.insert(63, QString(tr("Scrub repaired %1 blocks in %2 with %3 errors")).arg(numFixed, timeRun, numErr) );
	    }else{ 
	      if(LOGS.contains(60) && LOGS.value(60)!="FINISHED"){ newscrub=true; }
	      LOGS.insert(60,"FINISHED"); 
	      LOGS.insert(62, tr("Scrub completed") );
	      LOGS.insert(63, tr("Scrub completed without needing repairs") );
	    }
	    LOGS.insert(61,pool);
	    LOGS.insert(64, timestamp);
	    LOGS.insert(65, timestamp.section(" ",3,3) );
	    if(timer->interval() != sysCheckTime){ timer->start(sysCheckTime); }
          }else if(zstat[i].contains(" scrub cancel")){
	    //Scrub was cancelled before finishing
	    zstat[i]  = zstat[i].replace("\t"," ").simplified();
	    timestamp = zstat[i].section(" ",4,8,QString::SectionSkipEmpty);
	    LOGS.insert(60, "FINISHED");
	    LOGS.insert(61, pool);
	    LOGS.insert(62, QString(tr("Scrub cancelled for %1")).arg(pool) );
	    LOGS.insert(63, QString(tr("Scrub cancelled for %1")).arg(pool) );
	    LOGS.insert(64, timestamp);
	    LOGS.insert(65,timestamp.section(" ",3,3) );
	  }else{
	    //Scrub is running - parse the line
	    timestamp = zstat[i].section(" ",5,9,QString::SectionSkipEmpty);
	    i++; QString remain = zstat[i].section(" ",7,7,QString::SectionSkipEmpty);
	    i++; QString percent = zstat[i].section(" ",2,2,QString::SectionSkipEmpty);
	    if(LOGS.value(60) != "RUNNING"){newscrub=true;}
	    LOGS.insert(60,"RUNNING");
	    LOGS.insert(61,pool);
	    LOGS.insert(62, QString(tr("Scrubbing %1: %2 (%3 remaining)")).arg(pool, percent, remain) );
	    LOGS.insert(63, QString(tr("Scrubbing %1: %2 (%3 remaining)")).arg(pool, percent, remain) );
	    LOGS.insert(64, timestamp);
	    LOGS.insert(65, timestamp.section(" ",3,3) );
	    if(timer->interval() != 60000){ timer->start(60000); } //put the timer on a 1 minute refresh since it is running
	  }
	  if(LOGS.contains(50) ){
	    //Only resilvering OR scrub is shown at a time - so remove the resilver info
	    LOGS.remove(50);
	    LOGS.remove(51);
	    LOGS.remove(52);
	    LOGS.remove(53);
	    LOGS.remove(54);
	    LOGS.remove(55);
	  }
	// --------- RESILVERING -------
	}else if(zstat[i].contains("resilver in progress")){
	  //Resilvering is currently running
	  timestamp = zstat[i].section(" ",5,9,QString::SectionSkipEmpty);
	  //need info from the next two lines
	  i++; QString timeleft = zstat[i].section(" ",7,7,QString::SectionSkipEmpty);
	  i++; QString percent = zstat[i].section(" ", 2,2,QString::SectionSkipEmpty);
	  //Setup the running re-silvering progress
	  if(LOGS.value(50)!="RUNNING"){newresilver=true; }
	  LOGS.insert(50, "RUNNING");
	  // 51 - need to put the actual device in here (not available on this line)
	  LOGS.insert(52, QString(tr("Resilvering: %1 (%2 remaining)")).arg(percent, timeleft) );
	  if(newresilver){ LOGS.insert(53, QString(tr("Resilvering Started: %1 remaining ")).arg( timeleft) ); }
	  else{ LOGS.insert(53,QString(tr("Resilvering: %1 (%2 remaining)")).arg(percent, timeleft) ); }
	  LOGS.insert(54, timestamp);
	  LOGS.insert(55, timestamp.section(" ",3,3) );
	  if(LOGS.contains(60) ){
	    //Only resilvering OR scrub is shown at a time - so remove the scrub info
	    LOGS.remove(60);
	    LOGS.remove(61);
	    LOGS.remove(62);
	    LOGS.remove(63);
	    LOGS.remove(64);
	    LOGS.remove(65);
	  }
	  if(timer->interval() != 60000){ timer->start(60000); }//put the timer on a 1 minute refresh since it is running
	}else if(zstat[i].contains("resilvered")){
	  //Resilvering is finished
	  timestamp = zstat[i].section(" ",9,13,QString::SectionSkipEmpty);
	  QString timecomplete = zstat[i].section(" ",4,4,QString::SectionSkipEmpty);
	  QString errors = zstat[i].section(" ", 6,6,QString::SectionSkipEmpty);
	  //Setup the running re-silvering progress
	  if(LOGS.value(50) != "FINISHED" && LOGS.value(50) != "ERROR" ){newresilver=true; } //don't display message for first run
	  if(errors.toInt() > 0){ 
	    LOGS.insert(50, "ERROR");
	    LOGS.insert(52, QString(tr("Resilver completed in %1 with %2 errors")).arg(timecomplete, errors) );
	    LOGS.insert(53, QString(tr("Resilver completed in %1 with %2 errors")).arg(timecomplete, errors) );
	  }else{
	    LOGS.insert(50, "FINISHED");
	    LOGS.insert(52, QString(tr("Resilver completed successfully in %1")).arg(timecomplete) );
	    LOGS.insert(53, QString(tr("Resilver completed successfully in %1")).arg(timecomplete) ); 
          }
	  // 51 - need to put the actual device in here (not available on this line)
	  LOGS.insert(54, timestamp);
	  LOGS.insert(55, timestamp.section(" ",3,3) );
	  if(LOGS.contains(60) ){
	    //Only resilvering OR scrub is shown at a time - so remove the scrub info
	    LOGS.remove(60);
	    LOGS.remove(61);
	    LOGS.remove(62);
	    LOGS.remove(63);
	    LOGS.remove(64);
	    LOGS.remove(65);
	  }
	  if(timer->interval() != sysCheckTime){ timer->start(sysCheckTime); }
	}
      }else if(zstat[i].startsWith("errors:")){
	if(zstat[i] != "errors: No known data errors"){
	  qDebug() << "New zpool status error line that needs parsing:" << zstat[i];
	}
      }else if( state != "ONLINE" || !LOGS.value(50).isEmpty() ){
        //Check for state/resilvering of all real devices
	QString msg, summary, status;
	QString device = zstat[i].section(" ",0,0,QString::SectionSkipEmpty);
	if(zstat[i].contains("NAME STATE READ")){continue;} //nothing on this header line
	else if(zstat[i].contains("(resilvering)")){ LOGS.insert(51, device ); continue;}
	else if(zstat[i].contains("ONLINE")){continue;} //do nothing for this device - it is good
	else if(zstat[i].contains("OFFLINE")){ continue; } //do nothing - this status must be set manually - it is not a "random" status
        else if(zstat[i].contains("DEGRADED")){
	  // This should only happen on pools, not actual devices
	  cStat << "DEGRADED";
	  cMsg << tr("The pool is in a degraded state. See additional device error(s).");
	  cSummary << QString(tr("%1 is degraded.")).arg(device);
	  cDev << device;
	}else if(zstat[i].contains("FAULTED")){ 
	  cStat << "FAULTED";
	  cMsg << tr("The device is faulty, and should be replaced.");
	  cSummary << QString(tr("%1 is faulty.")).arg(device);
	  cDev << device;
	}else if(zstat[i].contains("REMOVED")){ 
	  cStat << "REMOVED";
	  cMsg << tr("The device was removed, and should be either be re-attached or replaced.");
	  cSummary << QString(tr("%1 was removed.")).arg(device);
	  cDev << device;
	}else if(zstat[i].contains("UNAVAIL")){ 
	  cStat << "UNAVAILABLE";
	  cMsg << tr("The device is unavailable and should be re-added to the pool.");
	  cSummary << QString(tr("%1 is unavailable.")).arg(device);
	  cDev << device;
	}
      }
    } //end of loop over zpool status lines
    
  //Add the critical messages to the hash
  if(cStat.isEmpty() || (cStat.join(" ").simplified() == "DEGRADED") ){
    //No errors, or the pool is degraded without any additional errors (usually because of a resilver going on)
    if(LOGS.contains(30)){
      LOGS.remove(30);
      LOGS.remove(31);
      LOGS.remove(32);
      LOGS.remove(33);
      LOGS.remove(34);
      LOGS.remove(35);
    }
  }else{
    if(LOGS.value(30) != cStat.join(":::") ){ newerror = true; }
    LOGS.insert(30, cStat.join(":::") );
    LOGS.insert(31, cDev.join(":::") );
    LOGS.insert(32, cSummary.join(":::") );
    LOGS.insert(33, cMsg.join(":::") );
    LOGS.insert(34, timestamp);
    LOGS.insert(35, timestamp.section(" ",3,3) );
  }
    
  //Now emit the appropriate signal
  if(newerror){ emit MessageAvailable("critical"); }
  else if(newresilver){ emit MessageAvailable("resilver"); }
  else if(newscrub){ emit MessageAvailable("scrub"); }
  else{ emit StatusUpdated(); }
}
Example #2
0
//PUBLIC
LPTray::LPTray() : QSystemTrayIcon() {
    qDebug() << "Starting up Life-preserver Tray...";
    //Start up the log file watcher and connect the signals/slots
    watcher = new LPWatcher();
    connect(watcher,SIGNAL(MessageAvailable(QString)),this,SLOT(watcherMessage(QString)) );
    connect(watcher,SIGNAL(StatusUpdated()),this,SLOT(watcherMessage()) );
    //Load the tray settings file
    settings = new QSettings(QSettings::UserScope,"PCBSD", "life-preserver-tray");
    //Create the notification option widgets
    nShowAll = new QRadioButton(tr("Show all"));
    naAll = new QWidgetAction(this);
    naAll->setDefaultWidget(nShowAll);
    nShowError = new QRadioButton(tr("Warnings Only"));
    naErr = new QWidgetAction(this);
    naErr->setDefaultWidget(nShowError);
    nShowNone = new QRadioButton(tr("None"));
    naNone = new QWidgetAction(this);
    naNone->setDefaultWidget(nShowNone);
    //Create notification menu
    notificationMenu = new QMenu(tr("Popup Settings"));
    notificationMenu->setIcon( QIcon(":/images/configure.png") );
    notificationMenu->addAction(naAll);
    notificationMenu->addAction(naErr);
    notificationMenu->addAction(naNone);
    //Activate the proper notification setting widget
    QString popset = settings->value("popup-policy", "").toString();
    qDebug() << "Current Popup Policy:" << popset;
    if(popset=="all") {
        nShowAll->setChecked(true);
        popupPolicy = 2;
    }
    else if(popset=="errors") {
        nShowError->setChecked(true);
        popupPolicy = 1;
    }
    else if(popset=="none") {
        nShowNone->setChecked(true);
        popupPolicy = 0;
    }
    else {
        nShowError->setChecked(true);
        settings->setValue("popup-policy","errors"); //save the proper setting
        popupPolicy = 1;
    }
    //Now connect the popup settings signals/slots
    connect(nShowAll, SIGNAL(clicked()), this, SLOT(changePopupPolicy()) );
    connect(nShowError, SIGNAL(clicked()), this, SLOT(changePopupPolicy()) );
    connect(nShowNone, SIGNAL(clicked()), this, SLOT(changePopupPolicy()) );
    //Setup the context menu
    menu = new QMenu;
    menu->addAction(QIcon(":/images/tray-icon-idle.png"),tr("Open Life Preserver"),this,SLOT(startGUI()) );
    menu->addSeparator();
    menu->addAction(QIcon(":/images/backup-failed.png"),tr("View Messages"),this,SLOT(startMessageDialog()) );
    menu->addMenu(notificationMenu);
    menu->addAction(QIcon(":/images/refresh.png"),tr("Refresh Tray"),this,SLOT(refreshStatus()) );
    menu->addSeparator();
    menu->addAction(QIcon(":/images/application-exit.png"),tr("Close Tray"),this,SLOT(slotClose()) );
    this->setContextMenu(menu);
    //Setup initial icon for the tray
    this->setIcon( QIcon(":/images/tray-icon-idle.png") );
    //Create the messages GUI
    msgdlg = new LPMessages();
    //connect other signals/slots
    connect(this, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(slotTrayClicked(QSystemTrayIcon::ActivationReason)) );
    //Start up the watcher
    watcher->start();
    updateTrayIcon();
    updateToolTip();
}