source: src-qt4/life-preserver/lp-gui/LPMain.cpp @ 54f447a

9.2-releasereleng/10.0releng/10.0.1releng/10.0.2releng/10.0.3
Last change on this file since 54f447a was 54f447a, checked in by Ken Moore <ken@…>, 11 months ago

Add a bunch of debugging output to lp-gui. See if this can help to narrow down where Kris/Josh? are having it crash.

  • Property mode set to 100644
File size: 29.0 KB
Line 
1#include "LPMain.h"
2#include "ui_LPMain.h"
3#include <unistd.h>
4
5LPMain::LPMain(QWidget *parent) : QMainWindow(parent), ui(new Ui::LPMain){
6  ui->setupUi(this); //load the Qt-designer UI file
7  //Create the basic/advanced view options
8  viewBasic = new QRadioButton(tr("Basic"), ui->menuView);
9        QWidgetAction *WABasic = new QWidgetAction(this); WABasic->setDefaultWidget(viewBasic);
10        ui->menuView->addAction(WABasic);
11  viewAdvanced = new QRadioButton(tr("Advanced"), ui->menuView);
12        QWidgetAction *WAAdv = new QWidgetAction(this); WAAdv->setDefaultWidget(viewAdvanced);
13        ui->menuView->addAction(WAAdv);
14  connect(viewBasic, SIGNAL(toggled(bool)), this, SLOT(viewChanged()) );
15  //Now set the default view type
16  viewBasic->setChecked(true); //will automatically call the "viewChanged" function
17  //Create the filesystem model and tie it to the treewidget
18  fsModel = new QFileSystemModel(this);
19        fsModel->setReadOnly(true);
20        ui->treeView->setModel(fsModel);
21  //Connect the UI to all the functions
22  connect(ui->tool_refresh, SIGNAL(clicked()), this, SLOT(updatePoolList()) );
23  connect(ui->combo_pools, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTabs()) );
24  connect(ui->combo_datasets, SIGNAL(currentIndexChanged(int)), this, SLOT(updateDataset()) );
25  connect(ui->slider_snapshots, SIGNAL(valueChanged(int)), this, SLOT(updateSnapshot()) );
26  connect(ui->push_prevsnap, SIGNAL(clicked()), this, SLOT(prevSnapshot()) );
27  connect(ui->push_nextsnap, SIGNAL(clicked()), this, SLOT(nextSnapshot()) );
28  connect(ui->check_hidden, SIGNAL(stateChanged(int)), this, SLOT(setFileVisibility()) );
29  connect(ui->push_restore, SIGNAL(clicked()), this, SLOT(restoreFiles()) );
30  connect(ui->push_configure, SIGNAL(clicked()), this, SLOT(openConfigGUI()) );
31  //Connect the Menu buttons
32  connect(ui->menuManage_Pool, SIGNAL(triggered(QAction*)), this, SLOT(menuAddPool(QAction*)) );
33  connect(ui->menuUnmanage_Pool, SIGNAL(triggered(QAction*)), this, SLOT(menuRemovePool(QAction*)) );
34  connect(ui->action_SaveKeyToUSB, SIGNAL(triggered()), this, SLOT(menuSaveSSHKey()) );
35  connect(ui->actionClose_Window, SIGNAL(triggered()), this, SLOT(menuCloseWindow()) );
36  connect(ui->menuCompress_Home_Dir, SIGNAL(triggered(QAction*)), this, SLOT(menuCompressHomeDir(QAction*)) );
37  connect(ui->actionExtract_Home_Dir, SIGNAL(triggered()), this, SLOT(menuExtractHomeDir()) );
38  connect(ui->actionAdd_Disk, SIGNAL(triggered()), this, SLOT(menuAddDisk()) );
39  connect(ui->menuRemove_Disk, SIGNAL(triggered(QAction*)), this, SLOT(menuRemoveDisk(QAction*)) );
40  connect(ui->menuSet_Disk_Offline, SIGNAL(triggered(QAction*)), this, SLOT(menuOfflineDisk(QAction*)) );
41  connect(ui->menuSet_Disk_Online, SIGNAL(triggered(QAction*)), this, SLOT(menuOnlineDisk(QAction*)) );
42  connect(ui->action_startScrub, SIGNAL(triggered()), this, SLOT(menuStartScrub()) );
43  connect(ui->action_stopScrub, SIGNAL(triggered()), this, SLOT(menuStopScrub()) );
44  connect(ui->action_newSnapshot, SIGNAL(triggered()), this, SLOT(menuNewSnapshot()) );
45  connect(ui->menuDelete_Snapshot, SIGNAL(triggered(QAction*)), this, SLOT(menuRemoveSnapshot(QAction*)) );
46  //Update the interface
47  QTimer::singleShot(0,this,SLOT(updatePoolList()) );
48 
49  //Make sure the status tab is shown initially
50  ui->tabWidget->setCurrentWidget(ui->tab_status);
51}
52
53LPMain::~LPMain(){
54       
55}
56
57// ==============
58//      PUBLIC SLOTS
59// ==============
60void LPMain::slotSingleInstance(){
61  this->raise();
62  this->show();
63}
64
65// ==============
66//          PRIVATE
67// ==============
68void LPMain::showErrorDialog(QString title, QString message, QString errors){
69  QMessageBox MB(QMessageBox::Warning, title, message, QMessageBox::Ok, this);
70    MB.setDetailedText(errors);
71    MB.exec();
72}
73
74void LPMain::showWaitBox(QString message){
75  if(waitBox == 0){
76    qDebug() << "New Wait Box";
77    waitBox = new QMessageBox(QMessageBox::NoIcon, tr("Please Wait"), message, QMessageBox::NoButton, this);
78    waitBox->setWindowModality(Qt::WindowModal);
79  }else{
80    qDebug() << "Update Wait Box:" << message;
81    waitBox->setText(message);
82  }
83  if(!waitBox->isVisible()){ waitBox->show(); waitBox->raise(); }
84  QCoreApplication::processEvents();
85}
86
87void LPMain::hideWaitBox(){
88  if(waitBox != 0){
89    if(waitBox->isVisible()){ waitBox->hide(); }
90  }
91       
92}
93
94// ==============
95//     PRIVATE SLOTS
96// ==============
97void LPMain::updatePoolList(){
98  //Get the currently selected pool (if there is one)
99  qDebug() << "Update Pool List";
100  QString cPool;
101  if(ui->combo_pools->currentIndex() != -1){ cPool = ui->combo_pools->currentText(); }
102  //Get the list of managed pools
103  qDebug() << "[DEBUG] Fetching list of pools";
104  QStringList pools = LPBackend::listDatasets();
105  QStringList poolsAvail = LPBackend::listPossibleDatasets();
106  //Now put the lists into the UI
107  ui->combo_pools->clear();
108  if(!pools.isEmpty()){ ui->combo_pools->addItems(pools); }
109  //Now set the currently selected pools
110  qDebug() << "[DEBUG] Pool list:" << pools;
111  if(pools.length() > 0){
112    poolSelected=true;   
113    int index = pools.indexOf(cPool);
114    if(index < 0){ ui->combo_pools->setCurrentIndex(0); }
115    else{ ui->combo_pools->setCurrentIndex(index); }
116  }else{
117    //No managed pools
118    poolSelected=false;
119    ui->combo_pools->addItem("No Managed Pools!");
120    ui->combo_pools->setCurrentIndex(0);
121  }
122  qDebug() << "[DEBUG] Update pool menu options";
123  //Now update the add/remove pool menu's
124  ui->menuManage_Pool->clear();
125  for( int i=0; i<poolsAvail.length(); i++){
126    if(pools.contains(poolsAvail[i])){ continue; } //already managed
127    ui->menuManage_Pool->addAction(poolsAvail[i]);
128  }
129  ui->menuManage_Pool->setEnabled( !ui->menuManage_Pool->isEmpty() );
130  ui->menuUnmanage_Pool->clear();
131  for( int i=0; i<pools.length(); i++){
132    ui->menuUnmanage_Pool->addAction(pools[i]);
133  }
134  ui->menuUnmanage_Pool->setEnabled( !ui->menuUnmanage_Pool->isEmpty() );
135  qDebug() << "[DEBUG] Update user menus";
136  //Now update the user's that are available for home-dir packaging
137  QDir hdir("/usr/home");
138  QStringList users = hdir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name);
139  ui->menuCompress_Home_Dir->clear();
140  for(int i=0; i<users.length(); i++){
141    ui->menuCompress_Home_Dir->addAction(users[i]);
142  }
143  //Now update the interface appropriately
144  ui->combo_pools->setEnabled(poolSelected);
145  qDebug() << "[DEBUG] Finished updatePoolList()";
146  updateTabs();
147}
148
149void LPMain::viewChanged(){
150  ui->menuView->hide();
151  ui->menubar->clear();
152  if(viewBasic->isChecked()){
153    ui->menubar->addMenu(ui->menuFile);
154    ui->menubar->addMenu(ui->menuView);
155    ui->menubar->addMenu(ui->menuClassic_Backups);
156  }else{
157    ui->menubar->addMenu(ui->menuFile);
158    ui->menubar->addMenu(ui->menuView);
159    ui->menubar->addMenu(ui->menuClassic_Backups);
160    ui->menubar->addMenu(ui->menuSnapshots);
161    ui->menubar->addMenu(ui->menuDisks);
162  }
163}
164
165void LPMain::updateTabs(){
166  //qDebug() << "Update Tabs" << poolSelected;
167  qDebug() << "[DEBUG] start updateTabs():" << poolSelected;
168  viewChanged();
169  ui->tabWidget->setEnabled(poolSelected);
170  ui->menuView->setEnabled(poolSelected);       
171  ui->menuDisks->setEnabled(poolSelected); 
172  ui->menuSnapshots->setEnabled(poolSelected);
173  ui->push_configure->setVisible(poolSelected);
174  ui->action_SaveKeyToUSB->setEnabled(poolSelected);
175  if(poolSelected){
176    showWaitBox(tr("Loading zpool information"));
177    qDebug() << "[DEBUG] loadPoolData:" << ui->combo_pools->currentText();
178    POOLDATA = LPGUtils::loadPoolData(ui->combo_pools->currentText());
179    qDebug() << "[DEBUG] loaded data";
180    hideWaitBox();
181    //Now list the status information
182    ui->label_status->setText(POOLDATA.poolStatus);
183    ui->label_numdisks->setText( QString::number(POOLDATA.harddisks.length()) );
184    ui->label_latestsnapshot->setText(POOLDATA.latestSnapshot);
185    if(POOLDATA.finishedStatus.isEmpty()){ ui->label_finishedstat->setVisible(false); }
186    else{
187      ui->label_finishedstat->setText(POOLDATA.finishedStatus);
188      ui->label_finishedstat->setVisible(true);
189    }
190    if(POOLDATA.runningStatus.isEmpty()){ ui->label_runningstat->setVisible(false); }
191    else{
192      ui->label_runningstat->setText(POOLDATA.runningStatus);
193      ui->label_runningstat->setVisible(true);
194    }       
195    if(POOLDATA.errorStatus.isEmpty()){ ui->label_errorstat->setVisible(false); }
196    else{
197      ui->label_errorstat->setText(POOLDATA.errorStatus);
198      ui->label_errorstat->setVisible(true);
199    }       
200    //Now list the data restore options
201    QString cds = ui->combo_datasets->currentText();
202    ui->combo_datasets->clear();
203    QStringList dslist = POOLDATA.subsets();
204    ui->combo_datasets->addItems(dslist);
205    int dsin = dslist.indexOf(cds);
206    if(dsin >= 0){ ui->combo_datasets->setCurrentIndex(dsin); }
207    else if( !dslist.isEmpty() ){ ui->combo_datasets->setCurrentIndex(0); }
208    else{ ui->combo_datasets->addItem(tr("No datasets available")); }
209    //NOTE: this automatically calls the "updateDataset()" function in a new thread
210   
211    //Now update the snapshot removal menu list
212    QStringList snaps = LPBackend::listLPSnapshots(ui->combo_pools->currentText());
213    ui->menuDelete_Snapshot->clear();
214    for(int i=0; i<snaps.length(); i++){
215       ui->menuDelete_Snapshot->addAction(snaps[i]);
216    }
217    ui->menuDelete_Snapshot->setEnabled( !ui->menuDelete_Snapshot->isEmpty() );
218    //Now update the disk menu items
219    ui->menuRemove_Disk->clear();
220    ui->menuSet_Disk_Offline->clear();
221    ui->menuSet_Disk_Online->clear();
222    for(int i=0; i<POOLDATA.harddisks.length(); i++){
223      ui->menuRemove_Disk->addAction(POOLDATA.harddisks[i]);
224      if(POOLDATA.harddiskStatus[i] == "OFFLINE"){
225        ui->menuSet_Disk_Online->addAction(POOLDATA.harddisks[i]);
226      }else{
227        ui->menuSet_Disk_Offline->addAction(POOLDATA.harddisks[i]);     
228      }
229    }
230    ui->menuRemove_Disk->setEnabled(!ui->menuRemove_Disk->isEmpty());
231    ui->menuSet_Disk_Offline->setEnabled(!ui->menuSet_Disk_Offline->isEmpty());
232    ui->menuSet_Disk_Online->setEnabled(!ui->menuSet_Disk_Online->isEmpty());
233  }else{
234    //No Pool selected
235    ui->label_numdisks->clear();
236    ui->label_latestsnapshot->clear();
237    ui->label_status->clear();
238          ui->label_errorstat->setVisible(false);
239          ui->label_runningstat->setVisible(false);
240          ui->label_finishedstat->setVisible(false);
241  }
242
243}
244
245void LPMain::updateDataset(){
246  //Update the snapshots for the currently selected dataset
247  QString cds = ui->combo_datasets->currentText();
248  if(POOLDATA.subsets().indexOf(cds) >= 0){
249    QStringList snaps = POOLDATA.snapshots(cds);
250      qDebug() << "Update Dataset";
251      ui->slider_snapshots->setEnabled(true);
252      ui->slider_snapshots->setMinimum(0);
253      int max = snaps.length() -1;
254      if(max < 0){ max = 0; ui->slider_snapshots->setEnabled(false); }
255      ui->slider_snapshots->setMaximum(max);
256      ui->slider_snapshots->setValue(max); //most recent snapshot
257      updateSnapshot();
258  }else{
259    ui->slider_snapshots->setEnabled(false);
260    ui->label_snapshot->clear();
261    ui->push_nextsnap->setEnabled(false);
262    ui->push_prevsnap->setEnabled(false);
263  }
264       
265}
266
267void LPMain::updateSnapshot(){
268  int sval = ui->slider_snapshots->value();
269  QStringList snaps = POOLDATA.snapshots(ui->combo_datasets->currentText());
270  //qDebug() << "Update Snapshot";
271  //Update the previous/next buttons
272  if(sval == ui->slider_snapshots->minimum() ){ ui->push_prevsnap->setEnabled(false); }
273  else{ ui->push_prevsnap->setEnabled(true); }
274  if(sval == ui->slider_snapshots->maximum() ){ ui->push_nextsnap->setEnabled(false); }
275  else{ ui->push_nextsnap->setEnabled(true); }
276  //Now update the snapshot viewer
277  if(snaps.isEmpty()){ ui->label_snapshot->clear(); ui->slider_snapshots->setEnabled(false); }
278  else{
279    QString snap = snaps.at(sval);
280    QString path = ui->combo_datasets->currentText() + "/.zfs/snapshot/"+snap;
281    //qDebug() << "Snapshot path:" << path;
282    ui->label_snapshot->setText(snap);
283    //Now update the snapshot view
284    ui->treeView->setRootIndex( fsModel->setRootPath(path) );
285   
286  }
287}
288
289void LPMain::nextSnapshot(){
290  ui->slider_snapshots->setValue( ui->slider_snapshots->value()+1 );
291}
292
293void LPMain::prevSnapshot(){
294  ui->slider_snapshots->setValue( ui->slider_snapshots->value()-1 );
295}
296
297void LPMain::setFileVisibility(){
298  if(ui->check_hidden->isChecked()){
299    fsModel->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden );
300  }else{
301    fsModel->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot );
302  }
303}
304
305void LPMain::restoreFiles(){
306  QString filePath = fsModel->filePath( ui->treeView->currentIndex() );
307  qDebug() << " Restore file(s):" << filePath;
308  QString destDir = filePath.remove("/.zfs/snapshot/"+ui->label_snapshot->text());
309        destDir.chop( filePath.section("/",-1).size()+1 ); //get rid of the filename at the end
310        while(!QFile::exists(destDir)){ destDir.chop( destDir.section("/",-1).size() +1); }
311  QString newFilePath = destDir+"/"+LPGUtils::generateReversionFileName(filePath, destDir);
312  //qDebug() << "Destination:" << newFilePath;
313  //Perform the reversion(s)
314  QStringList errors;
315  if(QFileInfo(filePath).isDir()){
316    //Is a directory
317    showWaitBox( QString(tr("Restoring Directory: %1")).arg(newFilePath) );
318    errors = LPGUtils::revertDir(filePath, newFilePath);
319    hideWaitBox();
320    if(!errors.isEmpty()){
321      qDebug() << "Failed Reversions:" << errors;
322      errors.prepend(tr("File destination(s) that could not be restored:")+"\n");
323      showErrorDialog(tr("Reversion Error"), tr("Some files could not be restored from the snapshot."), errors.join("\n") );
324    }else{
325      qDebug() << "Reversion successful";           
326      QMessageBox::information(this,tr("Restore Successful"),QString(tr("The following directory was succesfully restored: %1")).arg(newFilePath) );
327    }
328  }else{
329    //Just a single file
330    showWaitBox( QString(tr("Restoring file: %1")).arg(newFilePath) );
331    bool ok = LPGUtils::revertFile(filePath, newFilePath);
332    hideWaitBox();
333    if( !ok ){
334      qDebug() << "Failed Reversion:" << newFilePath;
335      errors << QString(tr("Snapshot file: %1")).arg(filePath);
336      errors << QString(tr("Destination: %1")).arg(newFilePath);
337      errors << tr("Please check that the destination directory exists and is writable");
338      showErrorDialog(tr("Reversion Error"), tr("The file could not be restored from the snapshot."), errors.join("\n") );
339    }else{
340      qDebug() << "Reversion successful";
341      QMessageBox::information(this,tr("Restore Successful"),QString(tr("The following file was succesfully restored: %1")).arg(newFilePath) );
342    }
343  }       
344       
345}
346
347void LPMain::openConfigGUI(){
348  qDebug() << "Open Configuration UI";
349  QString ds = ui->combo_pools->currentText();
350  if(ds.isEmpty()){ return; }
351  LPConfig CFG(this);
352  CFG.loadDataset(ds, LPBackend::listReplicationTargets().contains(ds));
353  CFG.exec();
354  //Now check for return values and update appropriately
355  bool change = false;
356  if(CFG.localChanged){
357    ui->statusbar->showMessage(QString(tr("Configuring dataset: %1")).arg(ds),0);
358    LPBackend::setupDataset(ds, CFG.localSchedule, CFG.localSnapshots);
359    ui->statusbar->clearMessage();
360    change = true;
361  }
362  if(CFG.remoteChanged){
363    change = true;
364    if(CFG.isReplicated){
365      ui->statusbar->showMessage(QString(tr("Configuring replication: %1")).arg(ds),0);
366      LPBackend::setupReplication(ds, CFG.remoteHost, CFG.remoteUser, CFG.remotePort, CFG.remoteDataset, CFG.remoteFreq);
367      QMessageBox::information(this,tr("Reminder"),tr("Don't forget to save your SSH key to a USB stick so that you can restore your system from the remote host later!!"));
368    }else{
369      ui->statusbar->showMessage(QString(tr("Removing replication: %1")).arg(ds),0);
370      LPBackend::removeReplication(ds);
371    }
372    ui->statusbar->clearMessage();
373  }
374  //Now update the UI if appropriate
375  if(change){
376    updateTabs();
377  }     
378}
379
380// -----------------------------------------------
381//   MENU SLOTS
382// -----------------------------------------------
383// ==== File Menu ====
384void LPMain::menuAddPool(QAction *act){
385  QString dataset = act->text();
386  qDebug() << "Start Wizard for new managing pool:" << dataset;
387  LPWizard wiz(this);
388  wiz.setDataset(dataset);
389  wiz.exec();
390  //See if the wizard was cancelled or not
391  if(!wiz.cancelled){
392    ui->statusbar->showMessage(QString(tr("Enabling dataset management: %1")).arg(dataset),0);
393    //run the proper commands to get the dataset enabled
394    if( LPBackend::setupDataset(dataset, wiz.localTime, wiz.totalSnapshots) ){
395      if(wiz.enableReplication){
396         LPBackend::setupReplication(dataset, wiz.remoteHost, wiz.remoteUser, wiz.remotePort, wiz.remoteDataset, wiz.remoteTime);     
397         QMessageBox::information(this,tr("Reminder"),tr("Don't forget to save your SSH key to a USB stick so that you can restore your system from the remote host later!!"));
398      }
399    }
400    ui->statusbar->clearMessage();
401    //Now update the list of pools
402    updatePoolList();
403  }     
404}
405
406void LPMain::menuRemovePool(QAction *act){
407  QString ds = act->text();
408  qDebug() << "Remove Pool:" << ds;
409  if(!ds.isEmpty()){
410    //Verify the removal of the dataset
411    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) ){           
412      //verify the removal of all the snapshots for this dataset
413      QStringList snaps = LPBackend::listLPSnapshots(ds);
414      if(!snaps.isEmpty()){
415        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) ){
416          //Remove all the snapshots
417          ui->statusbar->showMessage(QString(tr("%1: Removing snapshots")).arg(ds),0);
418          showWaitBox(tr("Removing snapshots"));
419          for(int i=0; i<snaps.length(); i++){
420            LPBackend::removeSnapshot(ds,snaps[i]);
421          }
422          ui->statusbar->clearMessage();
423        }
424      }
425      //Remove the dataset from life-preserver management
426      if(LPBackend::listReplicationTargets().contains(ds)){ 
427        ui->statusbar->showMessage(QString(tr("%1: Disabling Replication")).arg(ds),0);
428        showWaitBox(tr("Disabling Replication"));
429        LPBackend::removeReplication(ds); 
430        ui->statusbar->clearMessage();     
431      }
432      ui->statusbar->showMessage(QString(tr("%1: Disabling Life-Preserver Management")).arg(ds),0);
433      showWaitBox(tr("Removing Life Preserver Schedules"));
434      LPBackend::removeDataset(ds);
435      ui->statusbar->clearMessage();
436      updatePoolList();
437      hideWaitBox();
438    }
439  } //end check for empty ds
440
441}
442
443void LPMain::menuSaveSSHKey(){
444  QString ds = ui->combo_pools->currentText(); 
445  qDebug() << "Save SSH Key:" << ds;
446  if(ds.isEmpty()){ return; }
447  //Get the local hostname
448  char host[1023] = "\0";
449  gethostname(host,1023);
450  QString localHost = QString(host).simplified();
451  qDebug() << " - hostname:" << localHost;
452  //Scan for mounted USB devices
453  QStringList devs = LPBackend::findValidUSBDevices();
454  qDebug() << " - devs:" << devs;
455  if(devs.isEmpty()){
456    QMessageBox::warning(this,tr("No Valid USB Devices"), tr("No valid USB devices could be found. Please mount a FAT32 formatted USB stick and try again."));
457    return;
458  }
459  //Ask the user which one to save the file to
460  bool ok;
461  QString dev = QInputDialog::getItem(this, tr("Select USB Device"), tr("Available USB Devices:"), devs,0,false,&ok);   
462  if(!ok or dev.isEmpty()){ return; } //cancelled
463  QString devPath = dev.section("(",0,0).simplified();
464  //Now copy the file over
465  ok = LPBackend::copySSHKey(devPath, localHost);
466  if(ok){
467    QMessageBox::information(this,tr("Success"), tr("The public SSH key file was successfully copied onto the USB device."));
468  }else{
469    QMessageBox::information(this,tr("Failure"), tr("The public SSH key file could not be copied onto the USB device."));
470  }
471}
472
473void LPMain::menuCloseWindow(){
474  this->close();
475}
476
477// ==== Classic Backups Menu ====
478void LPMain::menuCompressHomeDir(QAction* act){
479  QString user = act->text();
480  qDebug() << "Compress Home Dir:" << user;
481  //Prompt for the package name
482  QString pkgName = user+"-"+QDateTime::currentDateTime().toString("yyyyMMdd-hhmm");
483  bool ok;
484  pkgName = QInputDialog::getText(this, tr("Package Name"), tr("Name of the package to create:"), QLineEdit::Normal, pkgName, &ok);
485  if(!ok || pkgName.isEmpty() ){ return; } //cancelled
486  //Now create the package
487  showWaitBox(tr("Packaging home directory"));
488  QString pkgPath = LPGUtils::packageHomeDir(user, pkgName);
489  hideWaitBox();
490  //Now inform the user of the result
491  if(pkgPath.isEmpty()){
492    qDebug() << "No Package created";
493    QMessageBox::warning(this,tr("Package Failure"), tr("The home directory package could not be created."));
494  }else{
495    qDebug() << "Package created at:" << pkgPath;
496    QMessageBox::information(this,tr("Package Success"), tr("The home directory package was successfully created.")+"\n\n"+pkgPath);
497  }       
498}
499
500void LPMain::menuExtractHomeDir(){
501  qDebug() << "Extract Home Dir";
502  //Get the file path from the user
503  QString filePath = QFileDialog::getOpenFileName(this,tr("Find Home Dir Package"), "/usr/home", tr("Home Dir Package (*.home.tar.gz)") );
504  if(filePath.isEmpty() || !QFile::exists(filePath)){ return; } //cancelled
505  //Now check if the user in the package is also on the system
506  QString username;
507  bool ok = LPGUtils::checkPackageUserPath(filePath, &username);
508  if(!ok){
509    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) );
510    return;
511  }
512  //Now extract the package
513  showWaitBox(tr("Extracting Home Directory"));
514  ok = LPGUtils::extractHomeDirPackage(filePath);
515  hideWaitBox();
516  //Now report the results
517  if(ok){
518    QMessageBox::information(this,tr("Package Extracted"), QString(tr("The package was successfully extracted within %1")).arg("/usr/home/"+username) );
519  }else{
520    QMessageBox::warning(this, tr("Package Failure"), QString(tr("The package could not be extracted within %1")).arg("/usr/home/"+username) );
521  }
522 
523}
524
525// ==== Disks Menu ====
526void LPMain::menuAddDisk(){
527  QString pool = ui->combo_pools->currentText();
528  //Get the available disks and remove the current disks
529  QStringList adisks = LPGUtils::listAvailableHardDisks();
530  for(int i=0; i<POOLDATA.harddisks.length(); i++){
531    adisks.removeAll( POOLDATA.harddisks[i].section("s",0,0,QString::SectionSkipEmpty) );
532  }
533  if(adisks.isEmpty()){
534    QMessageBox::information(this,tr("Attach New Disk"), tr("No available disks could be found"));
535    return;
536  }
537  //Find a disk that can be added to the system
538  bool ok=false;
539  QString disk = QInputDialog::getItem(this, tr("Attach New Disk"),tr("Detected Disks:"), adisks,0,false, &ok);
540  if( !ok || disk.isEmpty() ){ return; }
541  qDebug() << "Add Disk:" << disk << pool;
542  showWaitBox(tr("Attaching disk"));
543  ok = LPBackend::attachDisk(pool, disk);
544  hideWaitBox();
545  if(ok){
546    QMessageBox::information(this,tr("Disk Attached"),QString(tr("Success: %1 was added to %2")).arg(disk,pool) );
547    QTimer::singleShot(0,this,SLOT(updateTabs()) );
548  }else{
549    QMessageBox::warning(this,tr("Disk Attach Error"),QString(tr("Failure: %1 could not be attached to %2.")).arg(disk,pool) );
550  }     
551}
552
553void LPMain::menuRemoveDisk(QAction *act){
554  QString disk = act->text();
555  QString pool = ui->combo_pools->currentText();
556  //Verify action
557  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) ){
558    return; //cancelled
559  }
560  qDebug() << "Remove Disk:" << disk << pool;
561  showWaitBox(tr("Detaching disk"));
562  bool ok = LPBackend::detachDisk(pool, disk);
563  hideWaitBox();
564  if(ok){
565    QMessageBox::information(this,tr("Disk Removal Success"),QString(tr("Success: %1 was removed from %2")).arg(disk, pool) );
566    QTimer::singleShot(0,this,SLOT(updateTabs()) );
567  }else{
568    QMessageBox::warning(this,tr("Disk Removal Failure"),QString(tr("Failure: %1 could not be removed from %2 at this time.")).arg(disk, pool) );
569  }
570}
571
572void LPMain::menuOfflineDisk(QAction *act){
573  QString disk = act->text();
574  QString pool = ui->combo_pools->currentText();
575  //Verify action
576  if(QMessageBox::Yes != QMessageBox::question(this,tr("Verify Disk Offline"),QString(tr("Are you sure you wish to set %1 offline?")).arg(disk), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ){
577    return; //cancelled
578  }
579  qDebug() << "Offline Disk:" << disk << pool;
580  showWaitBox(tr("Setting disk offline"));
581  bool ok = LPBackend::setDiskOffline(pool, disk);
582  hideWaitBox();
583  if(ok){
584    QMessageBox::information(this,tr("Disk Offline Success"),QString(tr("Success: %1 has been taken offline.")).arg(disk) );
585    QTimer::singleShot(0,this,SLOT(updateTabs()) );
586  }else{
587    QMessageBox::warning(this,tr("Disk Offline Failure"),QString(tr("Failure: %1 could not be taken offline at this time.")).arg(disk) );
588  }
589}
590
591void LPMain::menuOnlineDisk(QAction *act){
592  QString disk = act->text();
593  QString pool = ui->combo_pools->currentText();
594  //Verify action
595  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) ){
596    return; //cancelled
597  }
598  qDebug() << "Online Disk:" << disk << pool;
599  showWaitBox(tr("Setting disk online"));
600  bool ok = LPBackend::setDiskOnline(pool, disk);
601  hideWaitBox();
602  if(ok){
603    QMessageBox::information(this,tr("Disk Online Success"),QString(tr("Success: %1 has been set online.")).arg(disk) );
604    QTimer::singleShot(0,this,SLOT(updateTabs()) );
605  }else{
606    QMessageBox::warning(this,tr("Disk Online Failure"),QString(tr("Failure: %1 could not be set online at this time.")).arg(disk) );
607  }
608}
609
610void LPMain::menuStartScrub(){
611  QString pool = ui->combo_pools->currentText();
612  //Verify starting a scrub
613  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) ){
614    return; //cancelled   
615  }
616  qDebug() << "Start Scrub:" << pool;
617  QString cmd = "zpool scrub "+pool;
618  showWaitBox(tr("Trying to start a scrub"));
619  int ret = system(cmd.toUtf8());
620  hideWaitBox();
621  if(ret == 0){
622    //Now let te user know that one has been triggered
623    QMessageBox::information(this,tr("Scrub Started"),QString(tr("A scrub has just been started on %1")).arg(pool));
624    QTimer::singleShot(0,this,SLOT(updateTabs()) );
625  }else{
626    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.") );
627  }
628}
629
630void LPMain::menuStopScrub(){
631  QString pool = ui->combo_pools->currentText();
632  //Verify stopping a scrub
633  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) ){
634    return; //cancelled   
635  }
636  qDebug() << "Stop Scrub:" << pool;
637  QString cmd = "zpool scrub -s "+pool;
638  showWaitBox(tr("Trying to stop scrub"));
639  int ret = system(cmd.toUtf8());
640  hideWaitBox();
641  if(ret == 0){
642    //Now let te user know that one has been triggered
643    QMessageBox::information(this,tr("Scrub Stopped"),QString(tr("The scrub on %1 has been stopped.")).arg(pool));
644    QTimer::singleShot(0,this,SLOT(updateTabs()) );
645  }else{
646    QMessageBox::warning(this,tr("Scrub Not Running"), QString(tr("There was no scrub running on %1.")).arg(pool) );
647  }     
648}
649
650// ==== Snapshots Menu ====
651void LPMain::menuNewSnapshot(){
652  qDebug() << "New Snapshot";
653  QString ds = ui->combo_pools->currentText();
654  if(ds.isEmpty()){return; }
655  //Get the new snapshot name from the user
656  bool ok;
657  QString name = QInputDialog::getText(this,tr("New Snapshot Name"), tr("Snapshot Name:"), QLineEdit::Normal, tr("Name"), &ok, 0, Qt::ImhUppercaseOnly | Qt::ImhLowercaseOnly | Qt::ImhDigitsOnly );
658  if(!ok || name.isEmpty()){ return; } //cancelled
659  qDebug() << "Creating a new snapshot:" << ds << name;
660  //Now create the new snapshot
661  LPBackend::newSnapshot(ds,name);
662  QMessageBox::information(this,tr("Snapshot Pending"), tr("The new snapshot creation has been added to the queue"));
663  updateTabs();
664}
665
666void LPMain::menuRemoveSnapshot(QAction *act){
667  QString snapshot = act->text();
668  QString pool = ui->combo_pools->currentText();
669  qDebug() << "Remove Snapshot:" << snapshot;
670  //verify snapshot removal
671  if( QMessageBox::Yes == QMessageBox::question(this,tr("Verify Snapshot Deletion"),QString(tr("Do you wish to delete this snapshot? %1")).arg(pool+"/"+snapshot)+"\n"+tr("WARNING: This is a permanant change that cannot be reversed"),QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ){
672    bool ok = LPBackend::removeSnapshot(ui->combo_pools->currentText(), snapshot);
673    if(ok){
674      QMessageBox::information(this,tr("Snapshot Removed"),tr("The snapshot was successfully deleted"));
675    }else{
676      QMessageBox::information(this,tr("Snapshot Removal Failure"),tr("The snapshot removal experienced an error and it not be completed at this time."));
677    }
678    updateTabs();
679  }
680}
Note: See TracBrowser for help on using the repository browser.