Browse files

Add the ability to create an SSH Key file, and copy that key file to …

…a msdosfs/FAT32 formatted USB stick (still needs testing)
  • Loading branch information...
1 parent 0de3f5a commit 96c5e841c3516cb304193e60a389258d3a54d9e6 @beanpole135 beanpole135 committed Aug 20, 2013
View
57 src-qt4/life-preserver/LPBackend.cpp
@@ -19,6 +19,7 @@ QStringList LPBackend::listPossibleDatasets(){
if(!ds.isEmpty()){ list << ds; }
}
list.removeDuplicates();
+
return list;
}
@@ -37,6 +38,7 @@ QStringList LPBackend::listDatasets(){
QString ds = out[i].section(" - ",0,0).simplified();
if(!ds.isEmpty()){ list << ds; }
}
+
return list;
}
@@ -60,6 +62,7 @@ QStringList LPBackend::listDatasetSubsets(QString dataset){
}
}
list.removeDuplicates();
+
return list;
}
@@ -90,6 +93,7 @@ QStringList LPBackend::listLPSnapshots(QString dataset){
if(!snap.isEmpty()){ list << snap; }
}
}
+
return list;
}
@@ -110,6 +114,7 @@ QStringList LPBackend::listReplicationTargets(){
if(!ds.isEmpty()){ list << ds; }
}
}
+
return list;
}
@@ -126,13 +131,15 @@ QStringList LPBackend::listCurrentStatus(){
//Now process the output
for(int i=2; i<out.length(); i++){ //first 2 lines are headers
//Format: <dataset>:::<lastsnapshot | NONE>:::<lastreplication | NONE>
+ if(out[i].isEmpty()){ continue; }
QString ds = out[i].section(" - ",0,0).simplified();
QString snap = out[i].section(" - ",1,1).simplified();
QString rep = out[i].section(" - ",2,2).simplified();
if(snap == "NONE"){ snap = "-"; }
if(rep == "NONE"){ rep = "-"; }
list << ds +":::"+ snap+":::"+rep;
}
+
return list;
}
@@ -151,12 +158,14 @@ bool LPBackend::setupDataset(QString dataset, int time, int numToKeep){
//Create the command
QString cmd = "lpreserver cronsnap "+dataset+" start "+freq+" "+QString::number(numToKeep);
int ret = system(cmd.toUtf8());
+
return (ret == 0);
}
bool LPBackend::removeDataset(QString dataset){
QString cmd = "lpreserver cronsnap "+dataset+" stop";
int ret = system(cmd.toUtf8());
+
return (ret == 0);
}
@@ -187,6 +196,7 @@ bool LPBackend::datasetInfo(QString dataset, int& time, int& numToKeep){
}
}
//qDebug() << "lpreserver cronsnap:\n" << out << QString::number(time) << QString::number(numToKeep);
+
return ok;
}
@@ -196,18 +206,21 @@ bool LPBackend::datasetInfo(QString dataset, int& time, int& numToKeep){
bool LPBackend::newSnapshot(QString dataset){
QString cmd = "lpreserver mksnap "+dataset;
int ret = system(cmd.toUtf8());
+
return (ret == 0);
}
bool LPBackend::removeSnapshot(QString dataset, QString snapshot){
QString cmd = "lpreserver rmsnap "+dataset +" "+snapshot;
int ret = system(cmd.toUtf8());
+
return (ret == 0);
}
bool LPBackend::revertSnapshot(QString dataset, QString snapshot){
QString cmd = "lpreserver revertsnap "+dataset +" "+snapshot;
int ret = system(cmd.toUtf8());
+
return (ret == 0);
}
@@ -267,12 +280,14 @@ bool LPBackend::setupReplication(QString dataset, QString remotehost, QString us
QString cmd = "lpreserver replicate add "+remotehost+" "+user+" "+ QString::number(port)+" "+dataset+" "+remotedataset+" "+stime;
int ret = system(cmd.toUtf8());
+
return (ret == 0);
}
bool LPBackend::removeReplication(QString dataset){
QString cmd = "lpreserver replicate remove "+dataset;
int ret = system(cmd.toUtf8());
+
return (ret == 0);
}
@@ -301,5 +316,47 @@ bool LPBackend::replicationInfo(QString dataset, QString& remotehost, QString& u
break;
}
}
+
+ return ok;
+}
+
+// ======================
+// SSH Key Management
+// ======================
+bool LPBackend::setupSSHKey(QString remoteHost, QString remoteUser, int remotePort){
+ QString LPPATH = "/usr/local/share/lifePreserver";
+ QString cmd = "xterm -e \""+LPPATH+"/scripts/setup-ssh-keys.sh "+remoteUser+" "+remoteHost+" "+QString::number(remotePort)+"\"";
+ int ret = system(cmd.toUtf8());
+ return (ret == 0);
+}
+
+QStringList LPBackend::findValidUSBDevices(){
+ //Return format: "<mountpoint> (<device node>")
+ QString cmd = "mount";
+ //Need output, so run this in a QProcess
+ QProcess *proc = new QProcess;
+ proc->setProcessChannelMode(QProcess::MergedChannels);
+ proc->start(cmd);
+ proc->waitForFinished();
+ QStringList out = QString(proc->readAllStandardOutput()).split("\n");
+ delete proc;
+ //Now process the output
+ QStringList list;
+ for(int i=0; i<out.length(); i++){
+ if(out[i].startsWith("/dev/da") && out[i].contains("(msdosfs,local)")){
+ QString mountpoint = out[i].section(" on ",1,1).section("(",0,0).simplified();
+ QString devnode = out[i].section(" on ",0,0).section("/",-1).simplified();
+ list << mountpoint +" ("+devnode+")";
+ }
+ }
+ return list;
+}
+
+bool LPBackend::copySSHKey(QString mountPath, QString localHost){
+ QString publicKey = "/root/.ssh/id_rsa.pub";
+ //copy the file onto the designated USB stick
+ if(!mountPath.endsWith("/")){ mountPath.append("/"); }
+ mountPath.append("root/.ssh/"+localHost+"-id_rsa.pub");
+ bool ok = QFile::copy(publicKey, mountPath);
return ok;
}
View
5 src-qt4/life-preserver/LPBackend.h
@@ -32,6 +32,9 @@ class LPBackend{
static bool setupReplication(QString dataset, QString remotehost, QString user, int port, QString remotedataset, int time);
static bool removeReplication(QString dataset);
static bool replicationInfo(QString dataset, QString& remotehost, QString& user, int& port, QString& remotedataset, int& time);
-
+ //SSH Key Management
+ static bool setupSSHKey(QString remoteHost, QString remoteUser, int remotePort);
+ static QStringList findValidUSBDevices();
+ static bool copySSHKey(QString mountPath, QString localHost);
};
#endif
View
73 src-qt4/life-preserver/LPConfig.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>400</width>
- <height>315</height>
+ <width>374</width>
+ <height>327</height>
</rect>
</property>
<property name="windowTitle">
@@ -175,34 +175,6 @@
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_5">
- <item row="0" column="0">
- <layout class="QHBoxLayout" name="horizontalLayout_8">
- <item>
- <widget class="QLabel" name="label_9">
- <property name="text">
- <string>Host Name</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLineEdit" name="lineHostName"/>
- </item>
- </layout>
- </item>
- <item row="1" column="0">
- <layout class="QHBoxLayout" name="horizontalLayout_7">
- <item>
- <widget class="QLabel" name="label_10">
- <property name="text">
- <string>User Name</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLineEdit" name="lineUserName"/>
- </item>
- </layout>
- </item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
@@ -273,6 +245,34 @@
</item>
</layout>
</item>
+ <item row="1" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_7">
+ <item>
+ <widget class="QLabel" name="label_10">
+ <property name="text">
+ <string>User Name</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="lineUserName"/>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_8">
+ <item>
+ <widget class="QLabel" name="label_9">
+ <property name="text">
+ <string>Host Name</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="lineHostName"/>
+ </item>
+ </layout>
+ </item>
<item row="4" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
@@ -323,6 +323,19 @@
</layout>
</widget>
</item>
+ <item row="5" column="0">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
</layout>
</widget>
</item>
View
2 src-qt4/life-preserver/LPTray.cpp
@@ -105,7 +105,7 @@ void LPTray::parseLogMessage(QString log){
//this->setIcon( QIcon(":/images/tray-icon-idle.png") );
}
if(GUI->isVisible()){
- GUI->updateDisplay();
+ GUI->setupUI();
}
}
View
BIN src-qt4/life-preserver/images/key.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
4 src-qt4/life-preserver/lPreserve.qrc
@@ -1,5 +1,7 @@
<RCC>
- <qresource prefix="" >
+ <qresource>
+ <file>images/upload.png</file>
+ <file>images/key.png</file>
<file>images/lifepreserver.png</file>
<file>images/backup-ok.png</file>
<file>images/backup-failed.png</file>
View
5 src-qt4/life-preserver/life-preserver.pro
@@ -27,6 +27,9 @@ FORMS = mainUI.ui \
TARGET=life-preserver
target.path=/usr/local/bin
+scripts.path=/usr/local/share/lifePreserver/scripts
+scripts.files=scripts/setup-ssh-keys.sh
+
images.path=/usr/local/share/lifePreserver/images/
images.files=images/lifepreserver.png
@@ -39,7 +42,7 @@ desktopperm.extra=chmod 644 /usr/local/share/applications/lifepreserver.desktop
dotrans.path=/usr/local/share/lifePreserver/i18n/
dotrans.extra=cd i18n && lrelease-qt4 -nounfinished *.ts && cp *.qm /usr/local/share/lifePreserver/i18n/
-INSTALLS += target dotrans images
+INSTALLS += target dotrans images scripts
TRANSLATIONS = i18n/LifePreserver_af.ts \
i18n/LifePreserver_ar.ts \
View
109 src-qt4/life-preserver/mainUI.cpp
@@ -14,29 +14,36 @@ mainUI::mainUI(QWidget *parent) : QMainWindow(parent), ui(new Ui::mainUI){
connect(revMenu,SIGNAL(triggered(QAction*)),this,SLOT(slotRevertToSnapshot(QAction*)) );
connect(brMenu,SIGNAL(triggered(QAction*)),this,SLOT(slotBrowseSnapshot(QAction*)) );
connect(addMenu, SIGNAL(triggered(QAction*)),this,SLOT(slotAddDataset(QAction*)) );
+ //Setup the Key menu items (static items, never changed)
+ keyMenu = new QMenu();
+ keyMenu->addAction(ui->actionKeyNew); //action from designer
+ keyMenu->addAction(ui->actionKeyCopy); //action from designer
+ ui->tool_keys->setMenu(keyMenu);
+ //Setup the update frequency limiter
+ freqTimer = new QTimer();
+ freqTimer->setSingleShot(true);
+ freqTimer->setInterval(15000);
+ connect(freqTimer, SIGNAL(timeout()), this, SLOT(setupUI()) );
}
mainUI::~mainUI(){
}
void mainUI::setupUI(){
- qDebug() << "Setting up Life Preserver UI...";
- //Initialize the Hash
- updateHash();
+ //Initialize the Hash (make sure it is not run too frequently - causes kernel panics)
+ if(lastUpdate.isNull() || lastUpdate.addSecs(15) < QTime::currentTime() ){
+ lastUpdate = QTime::currentTime();
+ qDebug() << "Updating the database";
+ updateHash();
+ }else{
+ freqTimer->start();
+ }
//Update the display
updateUI();
updateMenus();
}
-void mainUI::updateDisplay(){
- //Public function for the tray to be able to request that the UI update
- // (In case there is a status message that goes by which changes things)
- updateHash();
- updateUI();
- updateMenus();
-}
-
LPDataset mainUI::newDataset(QString ds){
//subroutine to create and fill a new dataset with system information
qDebug() << "New Dataset: " << ds;
@@ -64,15 +71,14 @@ LPDataset mainUI::newDataset(QString ds){
else{ ci++; }
}
if(CLIST.isEmpty()){ ci = -1; } //catch for empty list
-
- if(subsets.isEmpty()){
+ if(DSC.subsetHash.size() < 1){
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 if(ci > -1){
+ else if(ci > -1 && ci < CLIST.length()){
QString sna = CLIST[ci].section(":::",1,1);
if(sna != "-"){ DSC.latestSnapshot= sna; }
else{ DSC.latestSnapshot = ""; }
@@ -94,21 +100,27 @@ LPDataset mainUI::newDataset(QString ds){
// PRIVATE FUNCTIONS
// =================
void mainUI::updateHash(QString ds){
+ //qDebug() << "Get replication targets";
RLIST = LPBackend::listReplicationTargets(); //update list of replication datasets
+ //qDebug() << "Get possible datasets";
SLIST = LPBackend::listPossibleDatasets();
+ //qDebug() << "List current status";
CLIST = LPBackend::listCurrentStatus();
+ //qDebug() << "Check hash";
if(HLIST.contains(ds) && !ds.isEmpty()){
//only update the entry for the given dataset
HLIST.insert(ds, newDataset(ds)); //will overwrite the current entry in the hash
}else{
//Clear and fill the hash
+ //qDebug() << "Clear hash";
HLIST.clear();
+ //qDebug() << "List datasets";
QStringList dsList = LPBackend::listDatasets();
for(int i=0; i<dsList.length(); i++){
HLIST.insert( dsList[i], newDataset(dsList[i]) );
}
}
-
+ //qDebug() << "Done with Hash Update";
}
void mainUI::updateUI(){
@@ -145,10 +157,17 @@ void mainUI::updateMenus(){
if(ds.isEmpty()){
ui->tool_remove->setVisible(false);
ui->tool_config->setVisible(false);
+
}else{
ui->tool_remove->setVisible(true);
ui->tool_config->setVisible(true);
}
+ //Enabled/disable the SSH key management
+ if(RLIST.contains(ds) && !ds.isEmpty()){
+ ui->tool_keys->setVisible(true);
+ }else{
+ ui->tool_keys->setVisible(false);
+ }
//check for a valid ds/snapshot combination
bool ok = !ds.isEmpty();
if(ok){ ok = HLIST.contains(ds); }
@@ -224,9 +243,7 @@ void mainUI::on_tool_config_clicked(){
}
//Now update the UI if appropriate
if(change){
- updateHash(ds);
- updateUI();
- updateMenus();
+ setupUI();
}
}
@@ -250,9 +267,7 @@ void mainUI::on_tool_remove_clicked(){
LPBackend::removeDataset(ds);
}
}
- updateHash();
- updateUI();
- updateMenus();
+ setupUI();
}
@@ -330,15 +345,61 @@ void mainUI::slotAddDataset(QAction *act){
}
}
//Now update the UI/Hash
- updateHash();
- updateUI();
- updateMenus();
+ setupUI();
}
void mainUI::on_actionClose_triggered(){
this->close();
}
+void mainUI::on_actionKeyNew_triggered(){
+ QString ds = getSelectedDS();
+ qDebug() << "New SSH Key triggered for DS:" << ds;
+ //Get the remote values for this dataset
+ QString remoteHost, user, remotedataset;
+ int port, time;
+ bool ok = LPBackend::replicationInfo(ds, remoteHost, user, port, remotedataset, time);
+ if(ok){
+ if( !LPBackend::setupSSHKey(remoteHost, user, port) ){
+ QMessageBox::warning(this,tr("Failure"), tr("There was an error while creating the SSH key."));
+ }else{
+ QMessageBox::information(this,tr("Success"), tr("The SSH key was successfully generated."));
+ }
+ }else{
+ QMessageBox::warning(this,tr("Failure"), tr("There was an error in retrieving the remote replication information for this dataset. Please ensure that replication is enabled and try agin.") );
+ }
+}
+
+void mainUI::on_actionKeyCopy_triggered(){
+ QString ds = getSelectedDS();
+ qDebug() << "Copy SSH Key triggered for DS:" << ds;
+ //Get the local hostname
+ char host[1023] = "\0";
+ gethostname(host,1023);
+ QString localHost = QString(host).simplified();
+ qDebug() << " - hostname:" << localHost;
+ //Scan for mounted USB devices
+ QStringList devs = LPBackend::findValidUSBDevices();
+ qDebug() << " - devs:" << devs;
+ if(devs.isEmpty()){
+ 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."));
+ return;
+ }
+ //Ask the user which one to save the file to
+ bool ok;
+ QString dev = QInputDialog::getItem(this, tr("Select USB Device"), tr("Available USB Devices:"), devs,0,false,&ok);
+ if(!ok or dev.isEmpty()){ return; } //cancelled
+ QString devPath = dev.section("(",0,0).simplified();
+ //Now copy the file over
+ ok = LPBackend::copySSHKey(devPath, localHost);
+ if(ok){
+ QMessageBox::information(this,tr("Success"), tr("The public SSH key file was successfully copied onto the USB device."));
+ }else{
+ QMessageBox::information(this,tr("Failure"), tr("The public SSH key file could not be copied onto the USB device."));
+ }
+}
+
+
// =============
// PROTECTED
// =============
View
14 src-qt4/life-preserver/mainUI.h
@@ -10,6 +10,9 @@
#include <QMessageBox>
#include <QCloseEvent>
#include <QFileDialog>
+#include <QInputDialog>
+#include <QTime>
+#include <QTimer>
#include "LPBackend.h"
#include "LPWizard.h"
@@ -28,17 +31,20 @@ class mainUI : public QMainWindow{
public:
explicit mainUI(QWidget* parent = 0);
~mainUI();
- void setupUI();
- void updateDisplay(); //for the tray to call it as necessary
+
+public slots:
+ void setupUI(); //for the tray to call it as necessary
private:
Ui::mainUI *ui;
QHash<QString,LPDataset> HLIST;
QStringList RLIST; //datasets that have replication enabled
QStringList SLIST; //available datasets on the system
QStringList CLIST; //current status for all datasets
- QMenu *revMenu, *brMenu, *addMenu; //revert/browse menu's
+ QMenu *revMenu, *brMenu, *addMenu, *keyMenu; //button menu's
+ QTime lastUpdate;
+ QTimer *freqTimer;
void updateHash(QString ds="");
void updateUI();
@@ -56,6 +62,8 @@ private slots:
void slotAddDataset(QAction*);
void on_actionClose_triggered();
+ void on_actionKeyNew_triggered();
+ void on_actionKeyCopy_triggered();
protected:
void closeEvent(QCloseEvent*);
View
35 src-qt4/life-preserver/mainUI.ui
@@ -113,6 +113,23 @@
</widget>
</item>
<item>
+ <widget class="QToolButton" name="tool_keys">
+ <property name="statusTip">
+ <string>Manage SSH keys for replication authentication</string>
+ </property>
+ <property name="text">
+ <string>Key Setup</string>
+ </property>
+ <property name="icon">
+ <iconset resource="lPreserve.qrc">
+ <normaloff>:/images/key.png</normaloff>:/images/key.png</iconset>
+ </property>
+ <property name="popupMode">
+ <enum>QToolButton::InstantPopup</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -191,6 +208,24 @@
<string>Close Window</string>
</property>
</action>
+ <action name="actionKeyCopy">
+ <property name="icon">
+ <iconset resource="lPreserve.qrc">
+ <normaloff>:/images/upload.png</normaloff>:/images/upload.png</iconset>
+ </property>
+ <property name="text">
+ <string>Copy To USB Stick</string>
+ </property>
+ </action>
+ <action name="actionKeyNew">
+ <property name="icon">
+ <iconset resource="lPreserve.qrc">
+ <normaloff>:/images/list-add.png</normaloff>:/images/list-add.png</iconset>
+ </property>
+ <property name="text">
+ <string>Generate SSH Key</string>
+ </property>
+ </action>
</widget>
<resources>
<include location="lPreserve.qrc"/>

0 comments on commit 96c5e84

Please sign in to comment.