source: src-qt4/life-preserver/lp-gui/LPBackend.cpp @ 194a5d3

releng/10.0.1releng/10.0.2
Last change on this file since 194a5d3 was 194a5d3, checked in by Ken Moore <ken@…>, 5 months ago

Finish updating the main Life preserver GUI to reflect the new scheduling options in lpreserver.

  • Property mode set to 100644
File size: 11.8 KB
Line 
1#include "LPBackend.h"
2
3// ==============
4//     Informational
5// ==============
6QStringList LPBackend::listPossibleDatasets(){
7  QString cmd = "zpool list -H -o name";
8  QStringList out = LPBackend::getCmdOutput(cmd);
9  //Now process the output (one dataset per line - no headers)
10  QStringList list;
11  for(int i=0; i<out.length(); i++){
12    QString ds = out[i].section("/",0,0).simplified();
13    if(!ds.isEmpty()){ list << ds; }
14  }
15  list.removeDuplicates();
16   
17  return list; 
18}
19
20QStringList LPBackend::listDatasets(){
21  QString cmd = "lpreserver listcron";
22  QStringList out = LPBackend::getCmdOutput(cmd);
23  //Now process the output
24  QStringList list;
25  for(int i=2; i<out.length(); i++){ //skip the first two lines (headers)
26    QString ds = out[i].section(" - ",0,0).simplified();
27    if(!ds.isEmpty()){ list << ds; }
28  }
29   
30  return list;
31}
32
33QStringList LPBackend::listDatasetSubsets(QString dataset){
34  QString cmd = "zfs list -H -t filesystem -o name,mountpoint,mounted";
35  QStringList out = LPBackend::getCmdOutput(cmd);
36  //Now process the output (one dataset per line - no headers)
37  QStringList list;
38  for(int i=0; i<out.length(); i++){
39    if(out[i].startsWith(dataset+"/")){
40      if(out[i].section("\t",2,2,QString::SectionSkipEmpty).simplified() == "yes"){
41        QString ds = out[i].section("\t",1,1).simplified(); //save the mountpoint
42        if(!ds.isEmpty()){ list << ds; }
43      }
44    }
45  }
46  list.removeDuplicates();     
47   
48  return list;
49}
50
51QStringList LPBackend::listSnapshots(QString dsmountpoint){
52  //List all the snapshots available for the given dataset mountpoint
53  QDir dir(dsmountpoint+"/.zfs/snapshot");
54  QStringList list;
55  if(dir.exists()){
56    list = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Time | QDir::Reversed);
57  }
58  return list;
59}
60
61QStringList LPBackend::listLPSnapshots(QString dataset){
62  QString cmd = "lpreserver listsnap "+dataset;
63  QStringList out = LPBackend::getCmdOutput(cmd);
64  //Now process the output
65  QStringList list;
66  for(int i=0; i<out.length(); i++){ //oldest ->newest
67    if(out[i].startsWith(dataset+"@")){
68      QString snap = out[i].section("@",1,3).section(" ",0,0).simplified();;
69      if(!snap.isEmpty()){ list << snap; }
70    }
71  }
72   
73  return list; 
74}
75
76QStringList LPBackend::listReplicationTargets(){
77  QString cmd = "lpreserver replicate list";
78  QStringList out = LPBackend::getCmdOutput(cmd);
79  //Now process the output
80  QStringList list;
81  for(int i=0; i<out.length(); i++){
82    if(out[i].contains("->")){
83      QString ds = out[i].section("->",0,0).simplified();
84      if(!ds.isEmpty()){ list << ds; }
85    }
86  }
87   
88  return list;         
89}
90
91QStringList LPBackend::listCurrentStatus(){
92  QString cmd = "lpreserver status";
93  QStringList out = LPBackend::getCmdOutput(cmd);
94  //Now process the output     
95  QStringList list;
96  for(int i=2; i<out.length(); i++){ //first 2 lines are headers
97    //Format: <dataset>:::<lastsnapshot | NONE>:::<lastreplication | NONE>
98    if(out[i].isEmpty()){ continue; }
99    QString ds  = out[i].section(" - ",0,0).simplified();
100    QString snap = out[i].section(" - ",1,1).simplified();
101    QString rep = out[i].section(" - ",2,2).simplified();
102    if(snap == "NONE"){ snap = "-"; }
103    if(rep == "NONE"){ rep = "-"; }
104    list << ds +":::"+ snap+":::"+rep;
105  }
106   
107  return list;
108}
109
110// ==================
111//    Dataset Management
112// ==================
113bool LPBackend::setupDataset(QString dataset, int time, int numToKeep){
114  //Configure inputs
115  QString freq;
116  if(time == -60){ freq = "hourly"; }
117  if(time == -30){ freq = "30min"; }
118  else if(time == -10){ freq = "10min"; }
119  else if(time == -5){ freq = "5min"; }
120  else if(time >= 0 && time < 24){ freq = "daily@"+QString::number(time); }
121  else{ freq = "auto"; }
122 
123  //Create the command
124  QString cmd = "lpreserver cronsnap "+dataset+" start "+freq;
125  if(freq != "auto"){ cmd.append(" "+QString::number(numToKeep) ); } //also add the number to keep
126  int ret = LPBackend::runCmd(cmd);
127   
128  return (ret == 0);
129}
130
131bool LPBackend::removeDataset(QString dataset){
132  QString cmd = "lpreserver cronsnap "+dataset+" stop";
133  int ret = LPBackend::runCmd(cmd);
134   
135  return (ret == 0);
136}
137
138bool LPBackend::datasetInfo(QString dataset, int& time, int& numToKeep){
139  QString cmd = "lpreserver listcron";
140  QStringList out = LPBackend::getCmdOutput(cmd);
141  //Now process the output
142  bool ok = false;
143  for(int i=0; i<out.length(); i++){
144    if(out[i].section(" - ",0,0).simplified() == dataset){
145      //Get time schedule (in integer format)
146      QString sch = out[i].section(" - ",1,1).simplified();
147      if(sch.startsWith("daily@")){ time = sch.section("@",1,1).simplified().toInt(); }
148      else if(sch=="5min"){time = -5;}
149      else if(sch=="10min"){time = -10;}
150      else if(sch=="30min"){time = -30;}
151      else if(sch=="hourly"){ time = -60; } //hourly
152      else{ time = -999; } //auto
153      //Get total snapshots
154      numToKeep = out[i].section("- total:",1,1).simplified().toInt();
155      ok=true;
156      break;
157    }
158  }
159  //qDebug() << "lpreserver cronsnap:\n" << out << QString::number(time) << QString::number(numToKeep);
160   
161  return ok;
162}
163
164// ==================
165//    Snapshop Management
166// ==================
167void LPBackend::newSnapshot(QString dataset, QString snapshotname){
168  //This needs to run externally - since the snapshot is simply added to the queue, and the replication
169  //   afterwards may take a long time.
170  QString cmd = "lpreserver mksnap --replicate "+dataset+" "+snapshotname;
171  QProcess::startDetached(cmd);
172   
173  return;
174}
175
176bool LPBackend::removeSnapshot(QString dataset, QString snapshot){
177  QString cmd = "lpreserver rmsnap "+dataset +" "+snapshot;
178  int ret = LPBackend::runCmd(cmd);
179   
180  return (ret == 0);
181}
182
183bool LPBackend::revertSnapshot(QString dataset, QString snapshot){
184  QString cmd = "lpreserver revertsnap "+dataset +" "+snapshot;
185  int ret  = LPBackend::runCmd(cmd);
186   
187  return (ret == 0);
188}
189
190// ==================
191//    Replication Management
192// ==================
193bool LPBackend::setupReplication(QString dataset, QString remotehost, QString user, int port, QString remotedataset, int time){
194  QString stime = "sync"; //synchronize on snapshot creation (default)
195  if(time >= 0 && time < 24){ stime = QString::number(time); } //daily at a particular hour (24 hour notation)
196  else if(time == -60){ stime = "hour"; }
197  else if(time == -30){ stime = "30min"; }
198  else if(time == -10){ stime = "10min"; }
199 
200 
201  QString cmd = "lpreserver replicate add "+remotehost+" "+user+" "+ QString::number(port)+" "+dataset+" "+remotedataset+" "+stime;
202  int ret = LPBackend::runCmd(cmd);
203 
204  return (ret == 0);
205}
206
207bool LPBackend::removeReplication(QString dataset){
208  QString cmd = "lpreserver replicate remove "+dataset;
209  int ret = LPBackend::runCmd(cmd);     
210   
211  return (ret == 0);
212}
213
214bool LPBackend::replicationInfo(QString dataset, QString& remotehost, QString& user, int& port, QString& remotedataset, int& time){
215  QString cmd = "lpreserver replicate list";
216  QStringList out = LPBackend::getCmdOutput(cmd);
217  //Now process the output
218  bool ok = false;
219  for(int i=0; i<out.length(); i++){
220    if(out[i].contains("->") && out[i].startsWith(dataset)){
221      QString data = out[i].section("->",1,1);
222      user = data.section("@",0,0);
223      remotehost = data.section("@",1,1).section("[",0,0);
224      port = data.section("[",1,1).section("]",0,0).toInt();
225      remotedataset = data.section(":",1,1).section(" Time",0,0);
226      QString synchro = data.section("Time:",1,1).simplified();
227        if(synchro == "sync"){ time = -1; }
228        else if(synchro =="hour"){ time = -60; }
229        else if(synchro == "30min"){ time = -30; }
230        else if(synchro == "10min"){ time = -10; }
231        else{ time = synchro.toInt(); }
232      ok = true;
233      break;
234    }
235  }       
236   
237  return ok;
238}
239
240// ======================
241//          SSH Key Management
242// ======================
243bool LPBackend::setupSSHKey(QString remoteHost, QString remoteUser, int remotePort){
244  QString LPPATH = "/usr/local/share/lifePreserver";
245  QString cmd = "xterm -e \""+LPPATH+"/scripts/setup-ssh-keys.sh "+remoteUser+" "+remoteHost+" "+QString::number(remotePort)+"\"";
246  int ret = LPBackend::runCmd(cmd);
247  return (ret == 0);
248}
249
250QStringList LPBackend::findValidUSBDevices(){
251  //Return format: "<mountpoint> (<device node>")
252  QString cmd = "mount";
253  QStringList out = LPBackend::getCmdOutput(cmd);
254  //Now process the output
255  QStringList list;
256  for(int i=0; i<out.length(); i++){
257      if(out[i].startsWith("/dev/da") && out[i].contains("(msdosfs,")){
258      QString mountpoint = out[i].section(" on ",1,1).section("(",0,0).simplified();
259      QString devnode = out[i].section(" on ",0,0).section("/",-1).simplified();
260      list << mountpoint +" ("+devnode+")";
261    }
262  }
263  return list;
264}
265
266bool LPBackend::copySSHKey(QString mountPath, QString localHost){
267  QString publicKey = "/root/.ssh/id_rsa";
268  //copy the file onto the designated USB stick
269  if(!mountPath.endsWith("/")){ mountPath.append("/"); }
270  QDir lDir=mountPath + "lpreserver";
271  if ( ! lDir.exists() )
272     lDir.mkdir(lDir.path());
273
274  mountPath.append("lpreserver/"+localHost+"-id_rsa");
275
276  bool ok = QFile::copy(publicKey, mountPath);
277  return ok;
278}
279
280// ======================
281//        USB Device Management
282// ======================
283QStringList LPBackend::listDevices(){
284  //Scan the system for all valid da* and ada* devices (USB/SCSI, SATA)
285  //Return format: "<device node> (<device information>)"
286  QDir devDir("/dev");
287  QStringList devs = devDir.entryList(QStringList() << "da*"<<"ada*", QDir::System | QDir::NoSymLinks, QDir::Name);
288  QStringList camOut = LPBackend::getCmdOutput("camcontrol devlist");
289  QStringList output, flist;   
290  for(int i=0; i<devs.length(); i++){
291    flist = camOut.filter("("+devs[i]+",");
292    //still need to add an additional device filter to weed out devices currently in use.
293    if(!flist.isEmpty()){ output << devs[i] + " ("+flist[0].section(">",0,0).remove("<").simplified()+")"; }
294  }
295  return output;
296}
297
298bool LPBackend::isMounted(QString device){
299  qDebug() << "Device mount check not implemented yet:" << device;
300  return false;
301}
302
303bool LPBackend::unmountDevice(QString device){
304  qDebug() << "Device unmounting not implemented yet:" << device;
305  return false;
306}
307
308// ======================
309//        ZPOOL Disk Management
310// ======================
311bool LPBackend::attachDisk(QString pool, QString disk){
312  if( !disk.startsWith("/dev/") ){ disk.prepend("/dev/"); } //make sure it is the full disk path
313  if( !QFile::exists(disk) ){ return false; } //make sure the disk exists
314  QString cmd = "lpreserver zpool attach "+pool+" "+disk;
315  //Run the command
316  int ret = LPBackend::runCmd(cmd);
317  return (ret ==0);
318}
319
320bool LPBackend::detachDisk(QString pool, QString disk){
321  QString cmd = "lpreserver zpool detach "+pool+" "+disk;
322  //Run the command
323  int ret = LPBackend::runCmd(cmd);
324  return (ret ==0);     
325}
326
327bool LPBackend::setDiskOnline(QString pool, QString disk){
328  QString cmd = "lpreserver zpool online "+pool+" "+disk;
329  //Run the command
330  int ret = LPBackend::runCmd(cmd);
331  return (ret ==0);     
332}
333
334bool LPBackend::setDiskOffline(QString pool, QString disk){
335  QString cmd = "lpreserver zpool offline "+pool+" "+disk;
336  //Run the command
337  int ret = LPBackend::runCmd(cmd);
338  return (ret ==0);     
339}
340
341// =========================
342//             UTILITY FUNCTIONS
343// =========================
344QStringList LPBackend::getCmdOutput(QString cmd){
345  QProcess *proc = new QProcess;
346  proc->setProcessChannelMode(QProcess::MergedChannels);
347  proc->start(cmd);
348  while(!proc->waitForFinished(300)){
349    QCoreApplication::processEvents();
350  }
351  QStringList out = QString(proc->readAllStandardOutput()).split("\n"); 
352  delete proc; 
353  return out;
354}
355
356int LPBackend::runCmd(QString cmd, QStringList args){
357  QProcess *proc = new QProcess;
358  proc->setProcessChannelMode(QProcess::MergedChannels);
359  if(args.isEmpty()){   
360    proc->start(cmd);
361  }else{
362    proc->start(cmd, args);
363  }
364  while(!proc->waitForFinished(300)){
365    QCoreApplication::processEvents();
366  }
367  int ret = proc->exitCode();
368  delete proc; 
369  return ret;
370}
Note: See TracBrowser for help on using the repository browser.