Skip to content
Browse files

Get the new life preserver working with a new container class for all…

… the dataset information. This keeps a list of snapshots for each subset of the zpool.
  • Loading branch information...
1 parent 294caaf commit 632808522a96e2b98e266845f343cf754db5b0dc @beanpole135 beanpole135 committed Aug 13, 2013
View
24 life-preserver/LPBackend.cpp
@@ -41,7 +41,7 @@ QStringList LPBackend::listDatasets(){
}
QStringList LPBackend::listDatasetSubsets(QString dataset){
- QString cmd = "zfs list -H -t filesystem -o name";
+ QString cmd = "zfs list -H -t filesystem -o name,mountpoint,mounted";
//Need output, so run this in a QProcess
QProcess *proc = new QProcess;
proc->setProcessChannelMode(QProcess::MergedChannels);
@@ -51,15 +51,29 @@ QStringList LPBackend::listDatasetSubsets(QString dataset){
delete proc;
//Now process the output (one dataset per line - no headers)
QStringList list;
- for(int i=0; i<out.length(); i++){ //skip the first two lines (headers)
- QString ds = out[i].section("/",0,0).simplified();
- if(!ds.isEmpty()){ list << ds; }
+ for(int i=0; i<out.length(); i++){
+ if(out[i].startsWith(dataset+"/")){
+ if(out[i].section("\t",2,2,QString::SectionSkipEmpty).simplified() == "yes"){
+ QString ds = out[i].section("\t",1,1).simplified(); //save the mountpoint
+ if(!ds.isEmpty()){ list << ds; }
+ }
+ }
}
list.removeDuplicates();
return list;
}
-QStringList LPBackend::listSnapshots(QString dataset){
+QStringList LPBackend::listSnapshots(QString dsmountpoint){
+ //List all the snapshots available for the given dataset mountpoint
+ QDir dir(dsmountpoint+"/.zfs/snapshot");
+ QStringList list;
+ if(dir.exists()){
+ list = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name | QDir::Reversed);
+ }
+ return list;
+}
+
+QStringList LPBackend::listLPSnapshots(QString dataset){
QString cmd = "lpreserver listsnap "+dataset;
//Need output, so run this in a QProcess
QProcess *proc = new QProcess;
View
4 life-preserver/LPBackend.h
@@ -5,6 +5,7 @@
#include <QString>
#include <QStringList>
#include <QDebug>
+#include <QDir>
//Class of static functions for using the "lpreserver" backend
class LPBackend{
@@ -14,7 +15,8 @@ class LPBackend{
static QStringList listPossibleDatasets(); //list all possible datasets on the system
static QStringList listDatasets(); //list all current lifepreserver datasets
static QStringList listDatasetSubsets(QString dataset); //list all subsets of the main dataset
- static QStringList listSnapshots(QString dataset); //list all snapshots for a particular dataset
+ static QStringList listSnapshots(QString dsmountpoint); //list all snapshots for a particular dataset mountpoint
+ static QStringList listLPSnapshots(QString dataset); //list all snapshots created by life preserver
static QStringList listReplicationTargets(); //list all datasets with replication enabled
//Dataset Management
static bool setupDataset(QString dataset, int time, int numToKeep); //add or configure dataset
View
31 life-preserver/LPContainers.h
@@ -0,0 +1,31 @@
+#ifndef _LP_CONTAINERS_H
+#define _LP_CONTAINERS_H
+
+#include <QHash>
+#include <QStringList>
+#include <QString>
+
+
+class LPDataset{
+public:
+ LPDataset(){}
+ ~LPDataset(){}
+
+ //Information needed on each dataset
+ QString latestReplication;
+ QString latestSnapshot;
+ QString numberOfSnapshots;
+ QHash<QString,QStringList> subsetHash; //<subset, snapshot list> (complete dataset name should be <ds><subset>)
+
+ //Simplification functions for getting info from the hash
+ QStringList subsets(){ return QStringList(subsetHash.keys()); }
+ QStringList snapshots(QString subset){
+ if(subsetHash.contains(subset)){
+ return subsetHash[subset];
+ }else{
+ return QStringList();
+ }
+ }
+};
+
+#endif
View
2 life-preserver/LPTray.cpp
@@ -150,7 +150,7 @@ double LPTray::displayToDoubleK(QString displayNumber){
// PRIVATE SLOTS
// ===============
void LPTray::slotNewLogMessage(QString file){
- qDebug() << "New Log Message in file:" << file;
+ //qDebug() << "New Log Message in file:" << file;
if(file == "/var/log/lpreserver/lpreserver.log"){
//Backend Status Update
//get the last line from the log file
View
3 life-preserver/life-preserver.pro
@@ -7,7 +7,8 @@ CONFIG += qt warn_on release
HEADERS += LPTray.h \
mainUI.h \
LPBackend.h \
- LPWizard.h
+ LPWizard.h \
+ LPContainers.h
SOURCES += main.cpp \
LPTray.cpp \
View
6 life-preserver/main.cpp
@@ -17,6 +17,12 @@ int main( int argc, char ** argv )
if (a.isRunning())
return !(a.sendMessage("show"));
+ //Check whether running as root
+ if( getuid() != 0){
+ qDebug() << "Life-Preserver must be started as root!";
+ return 1;
+ }
+
QTranslator translator;
QLocale mylocale;
QString langCode = mylocale.name();
View
119 life-preserver/mainUI.cpp
@@ -37,27 +37,60 @@ void mainUI::updateDisplay(){
updateMenus();
}
+LPDataset mainUI::newDataset(QString ds){
+ //subroutine to create and fill a new dataset with system information
+ qDebug() << "New Dataset: " << ds;
+ LPDataset DSC;
+ //List all the mountpoints in this dataset
+ QStringList subsets = LPBackend::listDatasetSubsets(ds);
+ //populate the list of snapshots available for each mountpoint
+ for(int i=0; i<subsets.length(); i++){
+ //qDebug() << "Subset:" << subsets[i];
+ QStringList snaps = LPBackend::listSnapshots(subsets[i]);
+ //qDebug() << " - Snapshots:" << snaps;
+ if(snaps.isEmpty()){
+ //invalid subset - remove it from the list
+ subsets.removeAt(i);
+ i--;
+ }else{
+ DSC.subsetHash.insert(subsets[i],snaps); //add it to the internal container hash
+ }
+ }
+ //Get the time for the latest life-preserver snapshot (and total number)
+ if(subsets.isEmpty()){
+ DSC.numberOfSnapshots = "0";
+ DSC.latestSnapshot="";
+ }else{
+ QStringList fSnap = DSC.subsetHash[subsets[0]].filter("auto-"); //filtered snapshot list (just life preserver snapshots)
+ DSC.numberOfSnapshots = QString::number(fSnap.length());
+ if(fSnap.isEmpty()){ DSC.latestSnapshot=""; }
+ else{ DSC.latestSnapshot=fSnap[0]; }
+ }
+ //List the replication status
+ if(RLIST.contains(ds)){ DSC.latestReplication= tr("Enabled"); }
+ else{ DSC.latestReplication= tr("Disabled"); }
+ //Return the dataset
+ return DSC;
+}
+
// =================
// PRIVATE FUNCTIONS
// =================
void mainUI::updateHash(QString ds){
+ RLIST = LPBackend::listReplicationTargets(); //update list of replication datasets
+ SLIST = LPBackend::listPossibleDatasets();
if(HLIST.contains(ds) && !ds.isEmpty()){
//only update the entry for the given dataset
- QStringList snaps = LPBackend::listSnapshots(ds);
- snaps.sort();
- HLIST.insert(ds, snaps); //will overwrite the current entry in the hash
+ HLIST.insert(ds, newDataset(ds)); //will overwrite the current entry in the hash
}else{
//Clear and fill the hash
HLIST.clear();
QStringList dsList = LPBackend::listDatasets();
for(int i=0; i<dsList.length(); i++){
- QStringList snaps = LPBackend::listSnapshots(dsList[i]);
- //snaps.sort();
- HLIST.insert(dsList[i], snaps);
+ HLIST.insert( dsList[i], newDataset(dsList[i]) );
}
}
- RLIST = LPBackend::listReplicationTargets();
- SLIST = LPBackend::listPossibleDatasets();
+
}
void mainUI::updateUI(){
@@ -68,17 +101,9 @@ void mainUI::updateUI(){
// [ dataset, latest snapshot, num snapshots, is Replicated ]
QStringList cols;
cols << dsList[i]; //[0] - dataset
- int num = HLIST[dsList[i]].length();
- if(num > 0){
- cols << HLIST[dsList[i]].value(0); // [1] - newest snapshot name
- cols << QString::number(num); // [2] - total number of snapshots
- }else{
- cols << tr("NONE"); // [1] - newest snapshot name
- cols << "0"; // [2] - total number of snapshots
- }
- //Check for replication
- if(RLIST.contains(dsList[i])){ cols << tr("Yes"); } // [3] - is replicated
- else{ cols << tr("No"); } // [3] - is replicated
+ cols << HLIST[dsList[i]].latestSnapshot; // [1] newest snapshot name
+ cols << HLIST[dsList[i]].numberOfSnapshots; // [2] total number of snapshots
+ cols << HLIST[dsList[i]].latestReplication; // [3] latest replication
//Add the item to the widget
ui->treeWidget->addTopLevelItem( new QTreeWidgetItem(cols) );
}
@@ -109,17 +134,29 @@ void mainUI::updateMenus(){
//check for a valid ds/snapshot combination
bool ok = !ds.isEmpty();
if(ok){ ok = HLIST.contains(ds); }
- if(ok){ ok = (HLIST[ds].length() > 0); }
+ if(ok){ ok = (HLIST[ds].numberOfSnapshots.toInt() > 0); }
//Now set the items appropriately
revMenu->clear();
brMenu->clear();
if(ok){
//Reset the Menu Contents
- QStringList snaps = HLIST[ds];
- for(int i=0; i<snaps.length(); i++){
- revMenu->addAction( new QAction(snaps[i], this) );
- brMenu->addAction( new QAction(snaps[i], this) );
+ QStringList subsets = HLIST[ds].subsets();
+ for(int i=0; i<subsets.length(); i++){
+ //Build the menu of snapshots for this subset
+ QStringList snaps = HLIST[ds].snapshots(subsets[i]);
+ if(snaps.isEmpty()){ continue; }
+ QMenu *menu = new QMenu(subsets[i],this);
+ for(int s =0; s<snaps.length(); s++){
+ QAction *act = new QAction(snaps[s],this);
+ act->setWhatsThis(ds+":::"+subsets[i]+":::"+snaps[s]);
+ menu->addAction(act);
+ }
+ revMenu->addMenu(menu);
+ brMenu->addMenu(menu);
+ //
+ //revMenu->addAction( new QAction(snaps[i], this) );
+ //brMenu->addAction( new QAction(snaps[i], this) );
}
//Enable the buttons if appropriate
if(revMenu->isEmpty()){
@@ -165,14 +202,14 @@ void mainUI::on_tool_remove_clicked(){
//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
- 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
- QStringList snaps;
- if(HLIST.contains(ds)){ snaps = HLIST[ds]; }
- else{ snaps = LPBackend::listSnapshots(ds); }
- for(int i=0; i<snaps.length(); i++){
- LPBackend::removeSnapshot(ds,snaps[i]);
- }
+ QStringList snaps = LPBackend::listLPSnapshots(ds);
+ 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
+ for(int i=0; i<snaps.length(); i++){
+ LPBackend::removeSnapshot(ds,snaps[i]);
+ }
+ }
}
//Remove the dataset from life-preserver management
if(RLIST.contains(ds)){ LPBackend::removeReplication(ds); }
@@ -187,8 +224,13 @@ void mainUI::on_tool_remove_clicked(){
// --- Menu Items Clicked
void mainUI::slotRevertToSnapshot(QAction *act){
- QString snapshot = act->text();
- QString ds = getSelectedDS();
+ QString info = act->whatsThis();
+ QString ds = info.section(":::",0,0);
+ QString subset = info.section(":::",1,1);
+ QString snap = info.section(":::",2,2);
+ qDebug() << "Revert Clicked:" << ds << subset << snap;
+ return;
+ /*QString ds = getSelectedDS();
if(!ds.isEmpty()){
//Verify the reversion
if( QMessageBox::Yes == QMessageBox::question(this,tr("Verify Snapshot Reversion"),
@@ -203,11 +245,16 @@ void mainUI::slotRevertToSnapshot(QAction *act){
QMessageBox::information(this,tr("Reversion Success"), tr("The snapshot reversion was completed successfully."));
}
}
- }
+ }*/
}
void mainUI::slotBrowseSnapshot(QAction *act){
- QString snapshot = act->text();
+ QString info = act->whatsThis();
+ QString ds = info.section(":::",0,0);
+ QString subset = info.section(":::",1,1);
+ QString snap = info.section(":::",2,2);
+ qDebug() << "Browse Clicked:" << ds << subset << snap;
+ return;
}
void mainUI::slotAddDataset(QAction *act){
View
4 life-preserver/mainUI.h
@@ -12,6 +12,7 @@
#include "LPBackend.h"
#include "LPWizard.h"
+#include "LPContainers.h"
//TERMINOLOGY NOTE: DS=DataSet, SNAP=Snapshot
@@ -31,7 +32,7 @@ class mainUI : public QMainWindow{
private:
Ui::mainUI *ui;
- QHash<QString,QStringList> HLIST;
+ QHash<QString,LPDataset> HLIST;
QStringList RLIST; //datasets that have replication enabled
QStringList SLIST; //available datasets on the system
QMenu *revMenu, *brMenu, *addMenu; //revert/browse menu's
@@ -40,6 +41,7 @@ class mainUI : public QMainWindow{
void updateUI();
void updateMenus();
QString getSelectedDS();
+ LPDataset newDataset(QString);
private slots:
void on_treeWidget_itemSelectionChanged();

0 comments on commit 6328085

Please sign in to comment.
Something went wrong with that request. Please try again.