source: src-qt4/life-preserver/lp-gui/LPBackend.cpp @ 0ecb8f7

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

Update the classic package command so that it does not hang the UI while running

  • Property mode set to 100644
File size: 11.4 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 == -30){ freq = "30min"; }
117  else if(time == -10){ freq = "10min"; }
118  else if(time == -5){ freq = "5min"; }
119  else if(time >= 0 && time < 24){ freq = "daily@"+QString::number(time); }
120  else{ freq = "hourly"; }
121 
122  //Create the command
123  QString cmd = "lpreserver cronsnap "+dataset+" start "+freq+" "+QString::number(numToKeep);
124  int ret = LPBackend::runCmd(cmd);
125   
126  return (ret == 0);
127}
128
129bool LPBackend::removeDataset(QString dataset){
130  QString cmd = "lpreserver cronsnap "+dataset+" stop";
131  int ret = LPBackend::runCmd(cmd);
132   
133  return (ret == 0);
134}
135
136bool LPBackend::datasetInfo(QString dataset, int& time, int& numToKeep){
137  QString cmd = "lpreserver listcron";
138  QStringList out = LPBackend::getCmdOutput(cmd);
139  //Now process the output
140  bool ok = false;
141  for(int i=0; i<out.length(); i++){
142    if(out[i].section(" - ",0,0).simplified() == dataset){
143      //Get time schedule (in integer format)
144      QString sch = out[i].section(" - ",1,1).simplified();
145      if(sch.startsWith("daily@")){ time = sch.section("@",1,1).simplified().toInt(); }
146      else if(sch=="5min"){time = -5;}
147      else if(sch=="10min"){time = -10;}
148      else if(sch=="30min"){time = -30;}
149      else{ time = -60; } //hourly
150      //Get total snapshots
151      numToKeep = out[i].section("- total:",1,1).simplified().toInt();
152      ok=true;
153      break;
154    }
155  }
156  //qDebug() << "lpreserver cronsnap:\n" << out << QString::number(time) << QString::number(numToKeep);
157   
158  return ok;
159}
160
161// ==================
162//    Snapshop Management
163// ==================
164void LPBackend::newSnapshot(QString dataset, QString snapshotname){
165  //This needs to run externally - since the snapshot is simply added to the queue, and the replication
166  //   afterwards may take a long time.
167  QString cmd = "lpreserver mksnap --replicate "+dataset+" "+snapshotname;
168  QProcess::startDetached(cmd);
169   
170  return;
171}
172
173bool LPBackend::removeSnapshot(QString dataset, QString snapshot){
174  QString cmd = "lpreserver rmsnap "+dataset +" "+snapshot;
175  int ret = LPBackend::runCmd(cmd);
176   
177  return (ret == 0);
178}
179
180bool LPBackend::revertSnapshot(QString dataset, QString snapshot){
181  QString cmd = "lpreserver revertsnap "+dataset +" "+snapshot;
182  int ret  = LPBackend::runCmd(cmd);
183   
184  return (ret == 0);
185}
186
187// ==================
188//    Replication Management
189// ==================
190bool LPBackend::setupReplication(QString dataset, QString remotehost, QString user, int port, QString remotedataset, int time){
191  QString stime = "sync"; //synchronize on snapshot creation (default)
192  if(time >= 0 && time < 24){ stime = QString::number(time); } //daily at a particular hour (24 hour notation)
193 
194 
195  QString cmd = "lpreserver replicate add "+remotehost+" "+user+" "+ QString::number(port)+" "+dataset+" "+remotedataset+" "+stime;
196  int ret = LPBackend::runCmd(cmd);
197 
198  return (ret == 0);
199}
200
201bool LPBackend::removeReplication(QString dataset){
202  QString cmd = "lpreserver replicate remove "+dataset;
203  int ret = LPBackend::runCmd(cmd);     
204   
205  return (ret == 0);
206}
207
208bool LPBackend::replicationInfo(QString dataset, QString& remotehost, QString& user, int& port, QString& remotedataset, int& time){
209  QString cmd = "lpreserver replicate list";
210  QStringList out = LPBackend::getCmdOutput(cmd);
211  //Now process the output
212  bool ok = false;
213  for(int i=0; i<out.length(); i++){
214    if(out[i].contains("->") && out[i].startsWith(dataset)){
215      QString data = out[i].section("->",1,1);
216      user = data.section("@",0,0);
217      remotehost = data.section("@",1,1).section("[",0,0);
218      port = data.section("[",1,1).section("]",0,0).toInt();
219      remotedataset = data.section(":",1,1).section(" Time",0,0);
220      QString synchro = data.section("Time:",1,1).simplified();
221        if(synchro == "sync"){ time = -1; }
222        else{ time = synchro.toInt(); }
223      ok = true;
224      break;
225    }
226  }       
227   
228  return ok;
229}
230
231// ======================
232//          SSH Key Management
233// ======================
234bool LPBackend::setupSSHKey(QString remoteHost, QString remoteUser, int remotePort){
235  QString LPPATH = "/usr/local/share/lifePreserver";
236  QString cmd = "xterm -e \""+LPPATH+"/scripts/setup-ssh-keys.sh "+remoteUser+" "+remoteHost+" "+QString::number(remotePort)+"\"";
237  int ret = LPBackend::runCmd(cmd);
238  return (ret == 0);
239}
240
241QStringList LPBackend::findValidUSBDevices(){
242  //Return format: "<mountpoint> (<device node>")
243  QString cmd = "mount";
244  QStringList out = LPBackend::getCmdOutput(cmd);
245  //Now process the output
246  QStringList list;
247  for(int i=0; i<out.length(); i++){
248      if(out[i].startsWith("/dev/da") && out[i].contains("(msdosfs,")){
249      QString mountpoint = out[i].section(" on ",1,1).section("(",0,0).simplified();
250      QString devnode = out[i].section(" on ",0,0).section("/",-1).simplified();
251      list << mountpoint +" ("+devnode+")";
252    }
253  }
254  return list;
255}
256
257bool LPBackend::copySSHKey(QString mountPath, QString localHost){
258  QString publicKey = "/root/.ssh/id_rsa";
259  //copy the file onto the designated USB stick
260  if(!mountPath.endsWith("/")){ mountPath.append("/"); }
261  QDir lDir=mountPath + "lpreserver";
262  if ( ! lDir.exists() )
263     lDir.mkdir(lDir.path());
264
265  mountPath.append("lpreserver/"+localHost+"-id_rsa");
266
267  bool ok = QFile::copy(publicKey, mountPath);
268  return ok;
269}
270
271// ======================
272//        USB Device Management
273// ======================
274QStringList LPBackend::listDevices(){
275  //Scan the system for all valid da* and ada* devices (USB/SCSI, SATA)
276  //Return format: "<device node> (<device information>)"
277  QDir devDir("/dev");
278  QStringList devs = devDir.entryList(QStringList() << "da*"<<"ada*", QDir::System | QDir::NoSymLinks, QDir::Name);
279  QStringList camOut = LPBackend::getCmdOutput("camcontrol devlist");
280  QStringList output, flist;   
281  for(int i=0; i<devs.length(); i++){
282    flist = camOut.filter("("+devs[i]+",");
283    //still need to add an additional device filter to weed out devices currently in use.
284    if(!flist.isEmpty()){ output << devs[i] + " ("+flist[0].section(">",0,0).remove("<").simplified()+")"; }
285  }
286  return output;
287}
288
289bool LPBackend::isMounted(QString device){
290  qDebug() << "Device mount check not implemented yet:" << device;
291  return false;
292}
293
294bool LPBackend::unmountDevice(QString device){
295  qDebug() << "Device unmounting not implemented yet:" << device;
296  return false;
297}
298
299// ======================
300//        ZPOOL Disk Management
301// ======================
302bool LPBackend::attachDisk(QString pool, QString disk){
303  if( !disk.startsWith("/dev/") ){ disk.prepend("/dev/"); } //make sure it is the full disk path
304  if( !QFile::exists(disk) ){ return false; } //make sure the disk exists
305  QString cmd = "lpreserver zpool attach "+pool+" "+disk;
306  //Run the command
307  int ret = LPBackend::runCmd(cmd);
308  return (ret ==0);
309}
310
311bool LPBackend::detachDisk(QString pool, QString disk){
312  QString cmd = "lpreserver zpool detach "+pool+" "+disk;
313  //Run the command
314  int ret = LPBackend::runCmd(cmd);
315  return (ret ==0);     
316}
317
318bool LPBackend::setDiskOnline(QString pool, QString disk){
319  QString cmd = "lpreserver zpool online "+pool+" "+disk;
320  //Run the command
321  int ret = LPBackend::runCmd(cmd);
322  return (ret ==0);     
323}
324
325bool LPBackend::setDiskOffline(QString pool, QString disk){
326  QString cmd = "lpreserver zpool offline "+pool+" "+disk;
327  //Run the command
328  int ret = LPBackend::runCmd(cmd);
329  return (ret ==0);     
330}
331
332// =========================
333//             UTILITY FUNCTIONS
334// =========================
335QStringList LPBackend::getCmdOutput(QString cmd){
336  QProcess *proc = new QProcess;
337  proc->setProcessChannelMode(QProcess::MergedChannels);
338  proc->start(cmd);
339  while(!proc->waitForFinished(300)){
340    QCoreApplication::processEvents();
341  }
342  QStringList out = QString(proc->readAllStandardOutput()).split("\n"); 
343  delete proc; 
344  return out;
345}
346
347int LPBackend::runCmd(QString cmd, QStringList args){
348  QProcess *proc = new QProcess;
349  proc->setProcessChannelMode(QProcess::MergedChannels);
350  if(args.isEmpty()){   
351    proc->start(cmd);
352  }else{
353    proc->start(cmd, args);
354  }
355  while(!proc->waitForFinished(300)){
356    QCoreApplication::processEvents();
357  }
358  int ret = proc->exitCode();
359  delete proc; 
360  return ret;
361}
Note: See TracBrowser for help on using the repository browser.