// ==== Disks Menu ==== void LPMain::menuAddDisk(){ QString pool = ui->combo_pools->currentText(); //Get the available disks and remove the current disks QStringList adisks = LPGUtils::listAvailableHardDisks(); for(int i=0; i<POOLDATA.harddisks.length(); i++){ adisks.removeAll( POOLDATA.harddisks[i].section("s",0,0,QString::SectionSkipEmpty) ); } if(adisks.isEmpty()){ QMessageBox::information(this,tr("Attach New Disk"), tr("No available disks could be found")); return; } //Find a disk that can be added to the system bool ok=false; QString disk = QInputDialog::getItem(this, tr("Attach New Disk"),tr("Detected Disks:"), adisks,0,false, &ok); if( !ok || disk.isEmpty() ){ return; } qDebug() << "Add Disk:" << disk << pool; showWaitBox(tr("Attaching disk")); ok = LPBackend::attachDisk(pool, disk); hideWaitBox(); if(ok){ QMessageBox::information(this,tr("Disk Attached"),QString(tr("Success: %1 was added to %2")).arg(disk,pool) ); QTimer::singleShot(0,this,SLOT(updateTabs()) ); }else{ QMessageBox::warning(this,tr("Disk Attach Error"),QString(tr("Failure: %1 could not be attached to %2.")).arg(disk,pool) ); } }
void LPMain::restoreFiles(){ QString filePath = fsModel->filePath( ui->treeView->currentIndex() ); qDebug() << " Restore file(s):" << filePath; QFileInfo info(filePath); QString destDir = filePath; destDir.remove("/.zfs/snapshot/"+ui->label_snapshot->text()); destDir.chop( filePath.section("/",-1).size()+1 ); //get rid of the filename at the end while(!QFile::exists(destDir)){ destDir.chop( destDir.section("/",-1).size() +1); } QString newFilePath = destDir+"/"+LPGUtils::generateReversionFileName(filePath, destDir); //qDebug() << "Destination:" << newFilePath; //Perform the reversion(s) QStringList errors; if( info.isDir() ){ //Is a directory showWaitBox( QString(tr("Restoring Directory: %1")).arg(newFilePath) ); errors = LPGUtils::revertDir(filePath, newFilePath); hideWaitBox(); if(!errors.isEmpty()){ qDebug() << "Failed Reversions:" << errors; errors.prepend(tr("File destination(s) that could not be restored:")+"\n"); showErrorDialog(tr("Reversion Error"), tr("Some files could not be restored from the snapshot."), errors.join("\n") ); }else{ qDebug() << "Reversion successful"; QMessageBox::information(this,tr("Restore Successful"),QString(tr("The following directory was succesfully restored: %1")).arg(newFilePath) ); } }else{ //Just a single file showWaitBox( QString(tr("Restoring file: %1")).arg(newFilePath) ); bool ok = LPGUtils::revertFile(filePath, newFilePath); hideWaitBox(); if( !ok ){ qDebug() << "Failed Reversion:" << newFilePath; errors << QString(tr("Snapshot file: %1")).arg(filePath); errors << QString(tr("Destination: %1")).arg(newFilePath); errors << tr("Please check that the destination directory exists and is writable"); showErrorDialog(tr("Reversion Error"), tr("The file could not be restored from the snapshot."), errors.join("\n") ); }else{ qDebug() << "Reversion successful"; QMessageBox::information(this,tr("Restore Successful"),QString(tr("The following file was succesfully restored: %1")).arg(newFilePath) ); } } }
void LPMain::menuRemovePool(QAction *act){ QString ds = act->text(); qDebug() << "Remove Pool:" << ds; if(!ds.isEmpty()){ //Verify the removal of the dataset if( QMessageBox::Yes == QMessageBox::question(this,tr("Verify Dataset Backup Removal"),tr("Are you sure that you wish to cancel automated snapshots and/or replication of the following dataset?")+"\n\n"+ds,QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ){ //verify the removal of all the snapshots for this dataset QStringList snapComments; QStringList snaps = LPBackend::listLPSnapshots(ds, snapComments); if(!snaps.isEmpty()){ if( QMessageBox::Yes == QMessageBox::question(this,tr("Verify Snapshot Deletion"),tr("Do you wish to remove the local snapshots for this dataset?")+"\n"+tr("WARNING: This is a permanant change that cannot be reversed"),QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ){ //Remove all the snapshots ui->statusbar->showMessage(QString(tr("%1: Removing snapshots")).arg(ds),0); showWaitBox(tr("Removing snapshots")); for(int i=0; i<snaps.length(); i++){ LPBackend::removeSnapshot(ds,snaps[i]); } ui->statusbar->clearMessage(); } } //Remove the dataset from life-preserver management if(LPBackend::listReplicationTargets().contains(ds)){ ui->statusbar->showMessage(QString(tr("%1: Disabling Replication")).arg(ds),0); showWaitBox(tr("Disabling Replication")); //Need the replication host(s) QList<LPRepHost> rhosts = LPBackend::replicationInfo(ds); for(int i=0; i<rhosts.length(); i++){ LPBackend::removeReplication(ds,rhosts[i].host()); } ui->statusbar->clearMessage(); } if(LPBackend::listScrubs().contains(ds)){ ui->statusbar->showMessage(QString(tr("%1: Disabling Scrubs")).arg(ds),0); showWaitBox(tr("Disabling Scrubs")); LPBackend::removeScrub(ds); ui->statusbar->clearMessage(); } ui->statusbar->showMessage(QString(tr("%1: Disabling Life-Preserver Management")).arg(ds),0); showWaitBox(tr("Removing Life Preserver Schedules")); LPBackend::removeDataset(ds); ui->statusbar->clearMessage(); updatePoolList(); hideWaitBox(); } } //end check for empty ds }
void LPMain::menuOnlineDisk(QAction *act){ QString disk = act->text(); QString pool = ui->combo_pools->currentText(); //Verify action if(QMessageBox::Yes != QMessageBox::question(this,tr("Verify Disk Online"),QString(tr("Are you sure you wish to set %1 online?")).arg(disk), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ){ return; //cancelled } qDebug() << "Online Disk:" << disk << pool; showWaitBox(tr("Setting disk online")); bool ok = LPBackend::setDiskOnline(pool, disk); hideWaitBox(); if(ok){ QMessageBox::information(this,tr("Disk Online Success"),QString(tr("Success: %1 has been set online.")).arg(disk) ); QTimer::singleShot(0,this,SLOT(updateTabs()) ); }else{ QMessageBox::warning(this,tr("Disk Online Failure"),QString(tr("Failure: %1 could not be set online at this time.")).arg(disk) ); } }
void LPMain::menuRemoveDisk(QAction *act){ QString disk = act->text(); QString pool = ui->combo_pools->currentText(); //Verify action if(QMessageBox::Yes != QMessageBox::question(this,tr("Verify Disk Removal"),QString(tr("Are you sure that you want to remove %1 from %2?")).arg(disk,pool) + "\n\n" + tr("CAUTION: This disk can only be re-attached later as a brand new disk"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ){ return; //cancelled } qDebug() << "Remove Disk:" << disk << pool; showWaitBox(tr("Detaching disk")); bool ok = LPBackend::detachDisk(pool, disk); hideWaitBox(); if(ok){ QMessageBox::information(this,tr("Disk Removal Success"),QString(tr("Success: %1 was removed from %2")).arg(disk, pool) ); QTimer::singleShot(0,this,SLOT(updateTabs()) ); }else{ QMessageBox::warning(this,tr("Disk Removal Failure"),QString(tr("Failure: %1 could not be removed from %2 at this time.")).arg(disk, pool) ); } }
void LPMain::menuStopScrub(){ QString pool = ui->combo_pools->currentText(); //Verify stopping a scrub if( QMessageBox::Yes != QMessageBox::question(this,tr("Verify Scrub"),QString(tr("Are you sure you want to stop the scrub on %1?")).arg(pool), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ){ return; //cancelled } qDebug() << "Stop Scrub:" << pool; QString cmd = "zpool scrub -s "+pool; showWaitBox(tr("Trying to stop scrub")); int ret = system(cmd.toUtf8()); hideWaitBox(); if(ret == 0){ //Now let te user know that one has been triggered QMessageBox::information(this,tr("Scrub Stopped"),QString(tr("The scrub on %1 has been stopped.")).arg(pool)); QTimer::singleShot(0,this,SLOT(updateTabs()) ); }else{ QMessageBox::warning(this,tr("Scrub Not Running"), QString(tr("There was no scrub running on %1.")).arg(pool) ); } }
void LPMain::menuStartScrub(){ QString pool = ui->combo_pools->currentText(); //Verify starting a scrub if( QMessageBox::Yes != QMessageBox::question(this,tr("Verify Scrub"),QString(tr("Are you sure you want to start a scrub on %1?")).arg(pool) + "\n"+tr("NOTE: This may take quite a while to complete"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ){ return; //cancelled } qDebug() << "Start Scrub:" << pool; QString cmd = "zpool scrub "+pool; showWaitBox(tr("Trying to start a scrub")); int ret = system(cmd.toUtf8()); hideWaitBox(); if(ret == 0){ //Now let te user know that one has been triggered QMessageBox::information(this,tr("Scrub Started"),QString(tr("A scrub has just been started on %1")).arg(pool)); QTimer::singleShot(0,this,SLOT(updateTabs()) ); }else{ QMessageBox::warning(this,tr("Scrub Not Started"), QString(tr("A scrub on %1 could not be started at this time.")).arg(pool) + "\n"+tr("Please wait until any current resilvering or scrubs are finished before trying again.") ); } }
void LPMain::menuExtractHomeDir(){ qDebug() << "Extract Home Dir"; //Get the file path from the user QString filePath = QFileDialog::getOpenFileName(this,tr("Find Home Dir Package"), "/usr/home", tr("Home Dir Package (*.home.tar.gz)") ); if(filePath.isEmpty() || !QFile::exists(filePath)){ return; } //cancelled //Now check if the user in the package is also on the system QString username; bool ok = LPGUtils::checkPackageUserPath(filePath, &username); if(!ok){ QMessageBox::warning(this,tr("User Missing"),QString(tr("The user (%1) does not exist on this system. Please create this user first and then try again.")).arg(username) ); return; } //Now extract the package showWaitBox(tr("Extracting Home Directory")); ok = LPGUtils::extractHomeDirPackage(filePath); hideWaitBox(); //Now report the results if(ok){ QMessageBox::information(this,tr("Package Extracted"), QString(tr("The package was successfully extracted within %1")).arg("/usr/home/"+username) ); }else{ QMessageBox::warning(this, tr("Package Failure"), QString(tr("The package could not be extracted within %1")).arg("/usr/home/"+username) ); } }
void LPMain::updateTabs(){ //qDebug() << "Update Tabs" << poolSelected; qDebug() << "[DEBUG] start updateTabs():" << poolSelected; viewChanged(); ui->tabWidget->setEnabled(poolSelected); ui->menuView->setEnabled(poolSelected); ui->menuDisks->setEnabled(poolSelected); ui->menuSnapshots->setEnabled(poolSelected); ui->push_configure->setVisible(poolSelected); ui->action_SaveKeyToUSB->setEnabled(poolSelected); if(poolSelected){ showWaitBox(tr("Loading zpool information")); qDebug() << "[DEBUG] loadPoolData:" << ui->combo_pools->currentText(); POOLDATA = LPGUtils::loadPoolData(ui->combo_pools->currentText()); qDebug() << "[DEBUG] loaded data"; hideWaitBox(); //Now list the status information ui->label_status->setText(POOLDATA.poolStatus); ui->label_numdisks->setText( QString::number(POOLDATA.harddisks.length()) ); ui->label_latestsnapshot->setText(POOLDATA.latestSnapshot); if(POOLDATA.finishedStatus.isEmpty()){ ui->label_finishedstat->setVisible(false); } else{ ui->label_finishedstat->setText(POOLDATA.finishedStatus); ui->label_finishedstat->setVisible(true); } if(POOLDATA.runningStatus.isEmpty()){ ui->label_runningstat->setVisible(false); ui->action_startScrub->setEnabled(true); ui->action_stopScrub->setEnabled(false); }else{ ui->label_runningstat->setText(POOLDATA.runningStatus); ui->label_runningstat->setVisible(true); ui->action_startScrub->setEnabled(false); //Something already running ui->action_stopScrub->setEnabled(POOLDATA.runningStatus.contains("scrub", Qt::CaseInsensitive)); } if(POOLDATA.errorStatus.isEmpty()){ ui->label_errorstat->setVisible(false); } else{ ui->label_errorstat->setText(POOLDATA.errorStatus); ui->label_errorstat->setVisible(true); } //Now list the data restore options QString cds = ui->combo_datasets->currentText(); ui->combo_datasets->clear(); QStringList dslist = POOLDATA.subsets(); dslist.sort(); //Now move the home directories to the top of the list int moved = 0; for(int i=0; i<dslist.length(); i++){ //make sure it stays in alphabetical order if(dslist[i].startsWith("/usr/home/")){ dslist.move(i,moved); moved++; i--; //make sure to not miss any items from moving } } ui->combo_datasets->addItems(dslist); int dsin = dslist.indexOf(cds); if(dsin >= 0){ ui->combo_datasets->setCurrentIndex(dsin); } else if( !dslist.isEmpty() ){ ui->combo_datasets->setCurrentIndex(0); } else{ ui->combo_datasets->addItem(tr("No datasets available")); } //NOTE: this automatically calls the "updateDataset()" function in a new thread //Now update the snapshot removal menu list QStringList snaps = LPBackend::listLPSnapshots(ui->combo_pools->currentText()); ui->menuDelete_Snapshot->clear(); for(int i=0; i<snaps.length(); i++){ ui->menuDelete_Snapshot->addAction(snaps[i]); } ui->menuDelete_Snapshot->setEnabled( !ui->menuDelete_Snapshot->isEmpty() ); //Now update the disk menu items ui->menuRemove_Disk->clear(); ui->menuSet_Disk_Offline->clear(); ui->menuSet_Disk_Online->clear(); for(int i=0; i<POOLDATA.harddisks.length(); i++){ ui->menuRemove_Disk->addAction(POOLDATA.harddisks[i]); if(POOLDATA.harddiskStatus[i] == "OFFLINE"){ ui->menuSet_Disk_Online->addAction(POOLDATA.harddisks[i]); }else{ ui->menuSet_Disk_Offline->addAction(POOLDATA.harddisks[i]); } } ui->menuRemove_Disk->setEnabled(!ui->menuRemove_Disk->isEmpty()); ui->menuSet_Disk_Offline->setEnabled(!ui->menuSet_Disk_Offline->isEmpty()); ui->menuSet_Disk_Online->setEnabled(!ui->menuSet_Disk_Online->isEmpty()); }else{ //No Pool selected ui->label_numdisks->clear(); ui->label_latestsnapshot->clear(); ui->label_status->clear(); ui->label_errorstat->setVisible(false); ui->label_runningstat->setVisible(false); ui->label_finishedstat->setVisible(false); } }
void LPMain::updateTabs(){ static bool updating = false; if(updating){ return; } //prevent double-taps on this function updating = true; QApplication::processEvents(); //qDebug() << "Update Tabs" << poolSelected; qDebug() << "[DEBUG] start updateTabs():" << poolSelected; viewChanged(); ui->tabWidget->setEnabled(poolSelected); ui->menuView->setEnabled(poolSelected); ui->menuDisks->setEnabled(poolSelected); ui->menuSnapshots->setEnabled(poolSelected); ui->push_configure->setVisible(poolSelected); ui->action_SaveKeyToUSB->setEnabled(poolSelected); //No Pool selected (yet) ui->label_numdisks->clear(); ui->label_latestsnapshot->clear(); ui->label_status->clear(); ui->label_errorstat->setVisible(false); ui->label_runningstat->setVisible(false); ui->label_finishedstat->setVisible(false); if(poolSelected){ showWaitBox(tr("Loading zpool information")); qDebug() << "[DEBUG] loadPoolData:" << ui->combo_pools->currentText(); POOLDATA = LPGUtils::loadPoolData(ui->combo_pools->currentText()); qDebug() << "[DEBUG] loaded data"; hideWaitBox(); //Now list the status information ui->label_status->setText(POOLDATA.poolStatus); ui->label_numdisks->setText( QString::number(POOLDATA.harddisks.length()) ); ui->label_latestsnapshot->setText(POOLDATA.latestSnapshot); qDebug() << "[DEBUG] Latest Snapshot:" << POOLDATA.latestSnapshot; if(POOLDATA.finishedStatus.isEmpty()){ ui->label_finishedstat->setVisible(false); } else{ ui->label_finishedstat->setText(POOLDATA.finishedStatus); ui->label_finishedstat->setVisible(true); } if(POOLDATA.runningStatus.isEmpty()){ ui->label_runningstat->setVisible(false); ui->action_startScrub->setEnabled(true); ui->action_stopScrub->setEnabled(false); }else{ ui->label_runningstat->setText(POOLDATA.runningStatus); ui->label_runningstat->setVisible(true); ui->action_startScrub->setEnabled(false); //Something already running ui->action_stopScrub->setEnabled(POOLDATA.runningStatus.contains("scrub", Qt::CaseInsensitive)); } if(POOLDATA.errorStatus.isEmpty()){ ui->label_errorstat->setVisible(false); } else{ ui->label_errorstat->setText(POOLDATA.errorStatus); ui->label_errorstat->setVisible(true); } //Update the replication/disk menus QStringList repHosts = POOLDATA.repHost; ui->menuStart_Replication->clear(); ui->menuInit_Replications->clear(); for(int i=0; i<repHosts.length(); i++){ ui->menuStart_Replication->addAction( repHosts[i] ); ui->menuInit_Replications->addAction( repHosts[i] ); } ui->menuStart_Replication->setEnabled( !ui->menuStart_Replication->isEmpty() ); ui->menuInit_Replications->setEnabled( !ui->menuInit_Replications->isEmpty() ); //Now update the disk menu items ui->menuRemove_Disk->clear(); ui->menuSet_Disk_Offline->clear(); ui->menuSet_Disk_Online->clear(); for(int i=0; i<POOLDATA.harddisks.length(); i++){ ui->menuRemove_Disk->addAction(POOLDATA.harddisks[i]); if(POOLDATA.harddiskStatus[i] == "OFFLINE"){ ui->menuSet_Disk_Online->addAction(POOLDATA.harddisks[i]); }else{ ui->menuSet_Disk_Offline->addAction(POOLDATA.harddisks[i]); } } ui->menuRemove_Disk->setEnabled(!ui->menuRemove_Disk->isEmpty()); ui->menuSet_Disk_Offline->setEnabled(!ui->menuSet_Disk_Offline->isEmpty()); ui->menuSet_Disk_Online->setEnabled(!ui->menuSet_Disk_Online->isEmpty()); //Now list the data restore options QString cds = ui->combo_datasets->currentText(); ui->combo_datasets->clear(); ui->menuDelete_Snapshot->clear(); emit loadSnaps(&POOLDATA); //kickoff the snapshot loading in the background } QApplication::processEvents(); updating = false; }