6cb90ba3285199b6e62ecc5f0de2fc368704cb25
[tests.git] / system / TestPlc.py
1 # $Id$
2 import os, os.path
3 import datetime
4 import time
5 import sys
6 import traceback
7 from types import StringTypes
8
9 import utils
10 from TestSite import TestSite
11 from TestNode import TestNode
12 from TestUser import TestUser
13 from TestKey import TestKey
14 from TestSlice import TestSlice
15 from TestSliver import TestSliver
16 from TestBox import TestBox
17 from TestSsh import TestSsh
18 from TestApiserver import TestApiserver
19
20 # step methods must take (self) and return a boolean (options is a member of the class)
21
22 def standby(minutes,dry_run):
23     utils.header('Entering StandBy for %d mn'%minutes)
24     if dry_run:
25         print 'dry_run'
26     else:
27         time.sleep(60*minutes)
28     return True
29
30 def standby_generic (func):
31     def actual(self):
32         minutes=int(func.__name__.split("_")[1])
33         return standby(minutes,self.options.dry_run)
34     return actual
35
36 def node_mapper (method):
37     def actual(self):
38         overall=True
39         node_method = TestNode.__dict__[method.__name__]
40         for site_spec in self.plc_spec['sites']:
41             test_site = TestSite (self,site_spec)
42             for node_spec in site_spec['nodes']:
43                 test_node = TestNode (self,test_site,node_spec)
44                 if not node_method(test_node): overall=False
45         return overall
46     return actual
47
48 def slice_mapper_options (method):
49     def actual(self):
50         overall=True
51         slice_method = TestSlice.__dict__[method.__name__]
52         for slice_spec in self.plc_spec['slices']:
53             site_spec = self.locate_site (slice_spec['sitename'])
54             test_site = TestSite(self,site_spec)
55             test_slice=TestSlice(self,test_site,slice_spec)
56             if not slice_method(test_slice,self.options): overall=False
57         return overall
58     return actual
59
60 SEP='<sep>'
61
62 class TestPlc:
63
64     default_steps = ['uninstall','install','install_rpm', 
65                      'configure', 'start', SEP,
66                      'store_keys', 'clear_known_hosts', 'initscripts', SEP,
67                      'sites', 'nodes', 'slices', 'nodegroups', SEP,
68                      'init_node','bootcd', 'configure_qemu', 'export_qemu',
69                      'kill_all_qemus', 'reinstall_node','start_node', SEP,
70                      'nodes_booted', 'nodes_ssh', 'check_slice',
71                      'check_initscripts', 'check_tcp',SEP,
72                      'force_gather_logs', 'force_kill_qemus', 'force_record_tracker','force_free_tracker' ]
73     other_steps = [ 'stop_all_vservers','fresh_install', 'cache_rpm', 'stop', SEP,
74                     'clean_sites', 'clean_nodes', 'clean_slices', 'clean_keys', SEP,
75                     'show_boxes', 'list_all_qemus', 'list_qemus', SEP,
76                     'db_dump' , 'db_restore', ' cleanup_tracker',
77                     'standby_1 through 20'
78                     ]
79
80     @staticmethod
81     def printable_steps (list):
82         return " ".join(list).replace(" "+SEP+" "," \\\n")
83     @staticmethod
84     def valid_step (step):
85         return step != SEP
86
87     def __init__ (self,plc_spec,options):
88         self.plc_spec=plc_spec
89         self.options=options
90         self.test_ssh=TestSsh(self.plc_spec['hostname'],self.options.buildname)
91         try:
92             self.vserverip=plc_spec['vserverip']
93             self.vservername=plc_spec['vservername']
94             self.url="https://%s:443/PLCAPI/"%plc_spec['vserverip']
95             self.vserver=True
96         except:
97             raise Exception,'chroot-based myplc testing is deprecated'
98         self.apiserver=TestApiserver(self.url,options.dry_run)
99         
100     def name(self):
101         name=self.plc_spec['name']
102         return "%s.%s"%(name,self.vservername)
103
104     def hostname(self):
105         return self.plc_spec['hostname']
106
107     def is_local (self):
108         return self.test_ssh.is_local()
109
110     # define the API methods on this object through xmlrpc
111     # would help, but not strictly necessary
112     def connect (self):
113         pass
114
115     def actual_command_in_guest (self,command):
116         return self.test_ssh.actual_command(self.host_to_guest(command))
117     
118     def run_in_guest (self,command):
119         return utils.system(self.actual_command_in_guest(command))
120     
121     def run_in_host (self,command):
122         return self.test_ssh.run_in_buildname(command)
123
124     #command gets run in the vserver
125     def host_to_guest(self,command):
126         return "vserver %s exec %s"%(self.vservername,command)
127     
128     # xxx quick n dirty
129     def run_in_guest_piped (self,local,remote):
130         return utils.system(local+" | "+self.test_ssh.actual_command(self.host_to_guest(remote),keep_stdin=True))
131
132     def auth_root (self):
133         return {'Username':self.plc_spec['PLC_ROOT_USER'],
134                 'AuthMethod':'password',
135                 'AuthString':self.plc_spec['PLC_ROOT_PASSWORD'],
136                 'Role' : self.plc_spec['role']
137                 }
138     def locate_site (self,sitename):
139         for site in self.plc_spec['sites']:
140             if site['site_fields']['name'] == sitename:
141                 return site
142             if site['site_fields']['login_base'] == sitename:
143                 return site
144         raise Exception,"Cannot locate site %s"%sitename
145         
146     def locate_node (self,nodename):
147         for site in self.plc_spec['sites']:
148             for node in site['nodes']:
149                 if node['name'] == nodename:
150                     return (site,node)
151         raise Exception,"Cannot locate node %s"%nodename
152         
153     def locate_hostname (self,hostname):
154         for site in self.plc_spec['sites']:
155             for node in site['nodes']:
156                 if node['node_fields']['hostname'] == hostname:
157                     return (site,node)
158         raise Exception,"Cannot locate hostname %s"%hostname
159         
160     def locate_key (self,keyname):
161         for key in self.plc_spec['keys']:
162             if key['name'] == keyname:
163                 return key
164         raise Exception,"Cannot locate key %s"%keyname
165
166     def locate_slice (self, slicename):
167         for slice in self.plc_spec['slices']:
168             if slice['slice_fields']['name'] == slicename:
169                 return slice
170         raise Exception,"Cannot locate slice %s"%slicename
171
172     # all different hostboxes used in this plc
173     def gather_hostBoxes(self):
174         # maps on sites and nodes, return [ (host_box,test_node) ]
175         tuples=[]
176         for site_spec in self.plc_spec['sites']:
177             test_site = TestSite (self,site_spec)
178             for node_spec in site_spec['nodes']:
179                 test_node = TestNode (self, test_site, node_spec)
180                 if not test_node.is_real():
181                     tuples.append( (test_node.host_box(),test_node) )
182         # transform into a dict { 'host_box' -> [ test_node .. ] }
183         result = {}
184         for (box,node) in tuples:
185             if not result.has_key(box):
186                 result[box]=[node]
187             else:
188                 result[box].append(node)
189         return result
190                     
191     # a step for checking this stuff
192     def show_boxes (self):
193         for (box,nodes) in self.gather_hostBoxes().iteritems():
194             print box,":"," + ".join( [ node.name() for node in nodes ] )
195         return True
196
197     # make this a valid step
198     def kill_all_qemus(self):
199         # this is the brute force version, kill all qemus on that host box
200         for (box,nodes) in self.gather_hostBoxes().iteritems():
201             # pass the first nodename, as we don't push template-qemu on testboxes
202             nodedir=nodes[0].nodedir()
203             TestBox(box,self.options.buildname).kill_all_qemus(nodedir)
204         return True
205
206     # make this a valid step
207     def list_all_qemus(self):
208         for (box,nodes) in self.gather_hostBoxes().iteritems():
209             # this is the brute force version, kill all qemus on that host box
210             TestBox(box,self.options.buildname).list_all_qemus()
211         return True
212
213     # kill only the right qemus
214     def list_qemus(self):
215         for (box,nodes) in self.gather_hostBoxes().iteritems():
216             # the fine-grain version
217             for node in nodes:
218                 node.list_qemu()
219         return True
220
221     # kill only the right qemus
222     def kill_qemus(self):
223         for (box,nodes) in self.gather_hostBoxes().iteritems():
224             # the fine-grain version
225             for node in nodes:
226                 node.kill_qemu()
227         return True
228
229
230     ### utility methods for handling the pool of IP addresses allocated to plcs
231     # Logic
232     # (*) running plcs are recorded in the file named ~/running-test-plcs
233     # (*) this file contains a line for each running plc, older first
234     # (*) each line contains the vserver name + the hostname of the (vserver) testbox where it sits
235     # (*) the free_tracker method performs a vserver stop on the oldest entry
236     # (*) the record_tracker method adds an entry at the bottom of the file
237     # (*) the cleanup_tracker method stops all known vservers and removes the tracker file
238
239     TRACKER_FILE="~/running-test-plcs"
240
241     def record_tracker (self):
242         command="echo %s %s >> %s"%(self.vservername,self.test_ssh.hostname,TestPlc.TRACKER_FILE)
243         (code,output) = utils.output_of (self.test_ssh.actual_command(command))
244         if code != 0:
245             print "WARNING : COULD NOT record_tracker %s as a running plc on %s"%(self.vservername,self.test_ssh.hostname)
246             return False
247         print "Recorded %s in running plcs on host %s"%(self.vservername,self.test_ssh.hostname)
248         return True
249
250     def free_tracker (self):
251         command="head -1 %s"%TestPlc.TRACKER_FILE
252         (code,line) = utils.output_of(self.test_ssh.actual_command(command))
253         if code != 0:
254             print "No entry found in %s on %s"%(TestPlc.TRACKER_FILE,self.test_ssh.hostname)
255             return False
256         try:
257             [vserver_to_stop,hostname] = line.split()
258         except:
259             print "WARNING: free_tracker: Could not parse %s - skipped"%TestPlc.TRACKER_FILE
260             return False
261         stop_command = "vserver --silent %s stop"%vserver_to_stop
262         utils.system(self.test_ssh.actual_command(stop_command))
263         x=TestPlc.TRACKER_FILE
264         flush_command = "tail --lines=+2 %s > %s.tmp ; mv %s.tmp %s"%(x,x,x,x)
265         utils.system(self.test_ssh.actual_command(flush_command))
266         return True
267
268     # this should/could stop only the ones in TRACKER_FILE if that turns out to be reliable
269     def cleanup_tracker (self):
270         stop_all = "cd /vservers ; for i in * ; do vserver --silent $i stop ; done"
271         utils.system(self.test_ssh.actual_command(stop_all))
272         clean_tracker = "rm -f %s"%TestPlc.TRACKER_FILE
273         utils.system(self.test_ssh.actual_command(clean_tracker))
274
275     def uninstall(self):
276         self.run_in_host("vserver --silent %s delete"%self.vservername)
277         return True
278
279     ### install
280     def install(self):
281         # we need build dir for vtest-init-vserver
282         if self.is_local():
283             # a full path for the local calls
284             build_dir=os.path.dirname(sys.argv[0])+"/build"
285         else:
286             # use a standard name - will be relative to remote buildname
287             build_dir="build"
288         # run checkout in any case - would do an update if already exists
289         build_checkout = "svn checkout %s %s"%(self.options.build_url,build_dir)
290         if self.run_in_host(build_checkout) != 0:
291             return False
292         # the repo url is taken from arch-rpms-url 
293         # with the last step (i386.) removed
294         repo_url = self.options.arch_rpms_url
295         for level in [ 'arch' ]:
296             repo_url = os.path.dirname(repo_url)
297         if self.options.arch == "i386":
298             personality="-p linux32"
299         else:
300             personality="-p linux64"
301         create_vserver="%s/vtest-init-vserver.sh %s %s %s -- --interface eth0:%s"%\
302             (build_dir,personality,self.vservername,repo_url,self.vserverip)
303         return self.run_in_host(create_vserver) == 0
304
305     ### install_rpm 
306     def install_rpm(self):
307         return self.run_in_guest("yum -y install myplc-native")==0
308
309     ### 
310     def configure(self):
311         tmpname='%s.plc-config-tty'%(self.name())
312         fileconf=open(tmpname,'w')
313         for var in [ 'PLC_NAME',
314                      'PLC_ROOT_PASSWORD',
315                      'PLC_ROOT_USER',
316                      'PLC_MAIL_ENABLED',
317                      'PLC_MAIL_SUPPORT_ADDRESS',
318                      'PLC_DB_HOST',
319                      'PLC_API_HOST',
320                      'PLC_WWW_HOST',
321                      'PLC_BOOT_HOST',
322                      'PLC_NET_DNS1',
323                      'PLC_NET_DNS2']:
324             fileconf.write ('e %s\n%s\n'%(var,self.plc_spec[var]))
325         fileconf.write('w\n')
326         fileconf.write('q\n')
327         fileconf.close()
328         utils.system('cat %s'%tmpname)
329         self.run_in_guest_piped('cat %s'%tmpname,'plc-config-tty')
330         utils.system('rm %s'%tmpname)
331         return True
332
333     def start(self):
334         self.run_in_guest('service plc start')
335         return True
336         
337     def stop(self):
338         self.run_in_guest('service plc stop')
339         return True
340         
341     # could use a TestKey class
342     def store_keys(self):
343         for key_spec in self.plc_spec['keys']:
344                 TestKey(self,key_spec).store_key()
345         return True
346
347     def clean_keys(self):
348         utils.system("rm -rf %s/keys/"%os.path(sys.argv[0]))
349
350     def sites (self):
351         return self.do_sites()
352     
353     def clean_sites (self):
354         return self.do_sites(action="delete")
355     
356     def do_sites (self,action="add"):
357         for site_spec in self.plc_spec['sites']:
358             test_site = TestSite (self,site_spec)
359             if (action != "add"):
360                 utils.header("Deleting site %s in %s"%(test_site.name(),self.name()))
361                 test_site.delete_site()
362                 # deleted with the site
363                 #test_site.delete_users()
364                 continue
365             else:
366                 utils.header("Creating site %s & users in %s"%(test_site.name(),self.name()))
367                 test_site.create_site()
368                 test_site.create_users()
369         return True
370
371     def nodes (self):
372         return self.do_nodes()
373     def clean_nodes (self):
374         return self.do_nodes(action="delete")
375
376     def do_nodes (self,action="add"):
377         for site_spec in self.plc_spec['sites']:
378             test_site = TestSite (self,site_spec)
379             if action != "add":
380                 utils.header("Deleting nodes in site %s"%test_site.name())
381                 for node_spec in site_spec['nodes']:
382                     test_node=TestNode(self,test_site,node_spec)
383                     utils.header("Deleting %s"%test_node.name())
384                     test_node.delete_node()
385             else:
386                 utils.header("Creating nodes for site %s in %s"%(test_site.name(),self.name()))
387                 for node_spec in site_spec['nodes']:
388                     utils.pprint('Creating node %s'%node_spec,node_spec)
389                     test_node = TestNode (self,test_site,node_spec)
390                     test_node.create_node ()
391         return True
392
393     # create nodegroups if needed, and populate
394     # no need for a clean_nodegroups if we are careful enough
395     def nodegroups (self):
396         # 1st pass to scan contents
397         groups_dict = {}
398         for site_spec in self.plc_spec['sites']:
399             test_site = TestSite (self,site_spec)
400             for node_spec in site_spec['nodes']:
401                 test_node=TestNode (self,test_site,node_spec)
402                 if node_spec.has_key('nodegroups'):
403                     nodegroupnames=node_spec['nodegroups']
404                     if isinstance(nodegroupnames,StringTypes):
405                         nodegroupnames = [ nodegroupnames ]
406                     for nodegroupname in nodegroupnames:
407                         if not groups_dict.has_key(nodegroupname):
408                             groups_dict[nodegroupname]=[]
409                         groups_dict[nodegroupname].append(test_node.name())
410         auth=self.auth_root()
411         for (nodegroupname,group_nodes) in groups_dict.iteritems():
412             try:
413                 self.apiserver.GetNodeGroups(auth,{'name':nodegroupname})[0]
414             except:
415                 self.apiserver.AddNodeGroup(auth,{'name':nodegroupname})
416             for node in group_nodes:
417                 self.apiserver.AddNodeToNodeGroup(auth,node,nodegroupname)
418         return True
419
420     def all_hostnames (self) :
421         hostnames = []
422         for site_spec in self.plc_spec['sites']:
423             hostnames += [ node_spec['node_fields']['hostname'] \
424                            for node_spec in site_spec['nodes'] ]
425         return hostnames
426
427     # gracetime : during the first <gracetime> minutes nothing gets printed
428     def do_nodes_booted (self, minutes, gracetime,period=30):
429         if self.options.dry_run:
430             print 'dry_run'
431             return True
432         # compute timeout
433         timeout = datetime.datetime.now()+datetime.timedelta(minutes=minutes)
434         graceout = datetime.datetime.now()+datetime.timedelta(minutes=gracetime)
435         # the nodes that haven't checked yet - start with a full list and shrink over time
436         tocheck = self.all_hostnames()
437         utils.header("checking nodes %r"%tocheck)
438         # create a dict hostname -> status
439         status = dict ( [ (hostname,'undef') for hostname in tocheck ] )
440         while tocheck:
441             # get their status
442             tocheck_status=self.apiserver.GetNodes(self.auth_root(), tocheck, ['hostname','boot_state' ] )
443             # update status
444             for array in tocheck_status:
445                 hostname=array['hostname']
446                 boot_state=array['boot_state']
447                 if boot_state == 'boot':
448                     utils.header ("%s has reached the 'boot' state"%hostname)
449                 else:
450                     # if it's a real node, never mind
451                     (site_spec,node_spec)=self.locate_hostname(hostname)
452                     if TestNode.is_real_model(node_spec['node_fields']['model']):
453                         utils.header("WARNING - Real node %s in %s - ignored"%(hostname,boot_state))
454                         # let's cheat
455                         boot_state = 'boot'
456                     elif datetime.datetime.now() > graceout:
457                         utils.header ("%s still in '%s' state"%(hostname,boot_state))
458                         graceout=datetime.datetime.now()+datetime.timedelta(1)
459                 status[hostname] = boot_state
460             # refresh tocheck
461             tocheck = [ hostname for (hostname,boot_state) in status.iteritems() if boot_state != 'boot' ]
462             if not tocheck:
463                 return True
464             if datetime.datetime.now() > timeout:
465                 for hostname in tocheck:
466                     utils.header("FAILURE due to %s in '%s' state"%(hostname,status[hostname]))
467                 return False
468             # otherwise, sleep for a while
469             time.sleep(period)
470         # only useful in empty plcs
471         return True
472
473     def nodes_booted(self):
474         return self.do_nodes_booted(minutes=20,gracetime=15)
475
476     def do_nodes_ssh(self,minutes,gracetime,period=30):
477         # compute timeout
478         timeout = datetime.datetime.now()+datetime.timedelta(minutes=minutes)
479         graceout = datetime.datetime.now()+datetime.timedelta(minutes=gracetime)
480         tocheck = self.all_hostnames()
481 #        self.scan_publicKeys(tocheck)
482         utils.header("checking Connectivity on nodes %r"%tocheck)
483         while tocheck:
484             for hostname in tocheck:
485                 # try to ssh in nodes
486                 node_test_ssh = TestSsh (hostname,key="/etc/planetlab/root_ssh_key.rsa")
487                 success=self.run_in_guest(node_test_ssh.actual_command("hostname"))==0
488                 if success:
489                     utils.header('The node %s is sshable -->'%hostname)
490                     # refresh tocheck
491                     tocheck.remove(hostname)
492                 else:
493                     # we will have tried real nodes once, in case they're up - but if not, just skip
494                     (site_spec,node_spec)=self.locate_hostname(hostname)
495                     if TestNode.is_real_model(node_spec['node_fields']['model']):
496                         utils.header ("WARNING : check ssh access into real node %s - skipped"%hostname)
497                         tocheck.remove(hostname)
498                     elif datetime.datetime.now() > graceout:
499                         utils.header("Could not ssh-enter root context on %s"%hostname)
500             if  not tocheck:
501                 return True
502             if datetime.datetime.now() > timeout:
503                 for hostname in tocheck:
504                     utils.header("FAILURE to ssh into %s"%hostname)
505                 return False
506             # otherwise, sleep for a while
507             time.sleep(period)
508         # only useful in empty plcs
509         return True
510         
511     def nodes_ssh(self):
512         return self.do_nodes_ssh(minutes=6,gracetime=4)
513     
514     @node_mapper
515     def init_node (self): pass
516     @node_mapper
517     def bootcd (self): pass
518     @node_mapper
519     def configure_qemu (self): pass
520     @node_mapper
521     def reinstall_node (self): pass
522     @node_mapper
523     def export_qemu (self): pass
524         
525     def do_check_initscripts(self):
526         overall = True
527         for slice_spec in self.plc_spec['slices']:
528             if not slice_spec.has_key('initscriptname'):
529                 continue
530             initscript=slice_spec['initscriptname']
531             for nodename in slice_spec['nodenames']:
532                 (site,node) = self.locate_node (nodename)
533                 # xxx - passing the wrong site - probably harmless
534                 test_site = TestSite (self,site)
535                 test_slice = TestSlice (self,test_site,slice_spec)
536                 test_node = TestNode (self,test_site,node)
537                 test_sliver = TestSliver (self, test_node, test_slice)
538                 if not test_sliver.check_initscript(initscript):
539                     overall = False
540         return overall
541             
542     def check_initscripts(self):
543             return self.do_check_initscripts()
544                     
545     def initscripts (self):
546         for initscript in self.plc_spec['initscripts']:
547             utils.pprint('Adding Initscript in plc %s'%self.plc_spec['name'],initscript)
548             self.apiserver.AddInitScript(self.auth_root(),initscript['initscript_fields'])
549         return True
550
551     def slices (self):
552         return self.do_slices()
553
554     def clean_slices (self):
555         return self.do_slices("delete")
556
557     def do_slices (self,  action="add"):
558         for slice in self.plc_spec['slices']:
559             site_spec = self.locate_site (slice['sitename'])
560             test_site = TestSite(self,site_spec)
561             test_slice=TestSlice(self,test_site,slice)
562             if action != "add":
563                 utils.header("Deleting slices in site %s"%test_site.name())
564                 test_slice.delete_slice()
565             else:    
566                 utils.pprint("Creating slice",slice)
567                 test_slice.create_slice()
568                 utils.header('Created Slice %s'%slice['slice_fields']['name'])
569         return True
570         
571     @slice_mapper_options
572     def check_slice(self): pass
573
574     @node_mapper
575     def clear_known_hosts (self): pass
576     
577     @node_mapper
578     def start_node (self) : pass
579
580     def all_sliver_objs (self):
581         result=[]
582         for slice_spec in self.plc_spec['slices']:
583             slicename = slice_spec['slice_fields']['name']
584             for nodename in slice_spec['nodenames']:
585                 result.append(self.locate_sliver_obj (nodename,slicename))
586         return result
587
588     def locate_sliver_obj (self,nodename,slicename):
589         (site,node) = self.locate_node(nodename)
590         slice = self.locate_slice (slicename)
591         # build objects
592         test_site = TestSite (self, site)
593         test_node = TestNode (self, test_site,node)
594         # xxx the slice site is assumed to be the node site - mhh - probably harmless
595         test_slice = TestSlice (self, test_site, slice)
596         return TestSliver (self, test_node, test_slice)
597
598     def check_tcp (self):
599         specs = self.plc_spec['tcp_test']
600         overall=True
601         for spec in specs:
602             port = spec['port']
603             # server side
604             s_test_sliver = self.locate_sliver_obj (spec['server_node'],spec['server_slice'])
605             if not s_test_sliver.run_tcp_server(port,timeout=10):
606                 overall=False
607                 break
608
609             # idem for the client side
610             c_test_sliver = self.locate_sliver_obj(spec['server_node'],spec['server_slice'])
611             if not c_test_sliver.run_tcp_client(s_test_sliver.test_node.name(),port):
612                 overall=False
613         return overall
614     
615
616     def gather_logs (self):
617         # (1) get the plc's /var/log and store it locally in logs/myplc.var-log.<plcname>/*
618         # (2) get all the nodes qemu log and store it as logs/node.qemu.<node>.log
619         # (3) get the nodes /var/log and store is as logs/node.var-log.<node>/*
620         # (4) as far as possible get the slice's /var/log as logs/sliver.var-log.<sliver>/*
621         # (1)
622         print "-------------------- TestPlc.gather_logs : PLC's /var/log"
623         self.gather_var_logs ()
624         # (2) 
625         print "-------------------- TestPlc.gather_logs : nodes's QEMU logs"
626         for site_spec in self.plc_spec['sites']:
627             test_site = TestSite (self,site_spec)
628             for node_spec in site_spec['nodes']:
629                 test_node=TestNode(self,test_site,node_spec)
630                 test_node.gather_qemu_logs()
631         # (3)
632         print "-------------------- TestPlc.gather_logs : nodes's /var/log"
633         self.gather_nodes_var_logs()
634         # (4)
635         print "-------------------- TestPlc.gather_logs : sample sliver's /var/log"
636         self.gather_slivers_var_logs()
637         return True
638
639     def gather_slivers_var_logs(self):
640         for test_sliver in self.all_sliver_objs():
641             remote = test_sliver.tar_var_logs()
642             utils.system("mkdir -p logs/sliver.var-log.%s"%test_sliver.name())
643             command = remote + " | tar -C logs/sliver.var-log.%s -xf -"%test_sliver.name()
644             utils.system(command)
645         return True
646
647     def gather_var_logs (self):
648         to_plc = self.actual_command_in_guest("tar -C /var/log/ -cf - .")        
649         command = to_plc + "| tar -C logs/myplc.var-log.%s -xf -"%self.name()
650         utils.system("mkdir -p logs/myplc.var-log.%s"%self.name())
651         utils.system(command)
652
653     def gather_nodes_var_logs (self):
654         for site_spec in self.plc_spec['sites']:
655             test_site = TestSite (self,site_spec)
656             for node_spec in site_spec['nodes']:
657                 test_node=TestNode(self,test_site,node_spec)
658                 test_ssh = TestSsh (test_node.name(),key="/etc/planetlab/root_ssh_key.rsa")
659                 to_plc = self.actual_command_in_guest ( test_ssh.actual_command("tar -C /var/log -cf - ."))
660                 command = to_plc + "| tar -C logs/node.var-log.%s -xf -"%test_node.name()
661                 utils.system("mkdir -p logs/node.var-log.%s"%test_node.name())
662                 utils.system(command)
663
664
665     # returns the filename to use for sql dump/restore, using options.dbname if set
666     def dbfile (self, database):
667         # uses options.dbname if it is found
668         try:
669             name=self.options.dbname
670             if not isinstance(name,StringTypes):
671                 raise Exception
672         except:
673             t=datetime.datetime.now()
674             d=t.date()
675             name=str(d)
676         return "/root/%s-%s.sql"%(database,name)
677
678     def db_dump(self):
679         dump=self.dbfile("planetab4")
680         self.run_in_guest('pg_dump -U pgsqluser planetlab4 -f '+ dump)
681         utils.header('Dumped planetlab4 database in %s'%dump)
682         return True
683
684     def db_restore(self):
685         dump=self.dbfile("planetab4")
686         ##stop httpd service
687         self.run_in_guest('service httpd stop')
688         # xxx - need another wrapper
689         self.run_in_guest_piped('echo drop database planetlab4','psql --user=pgsqluser template1')
690         self.run_in_guest('createdb -U postgres --encoding=UNICODE --owner=pgsqluser planetlab4')
691         self.run_in_guest('psql -U pgsqluser planetlab4 -f '+dump)
692         ##starting httpd service
693         self.run_in_guest('service httpd start')
694
695         utils.header('Database restored from ' + dump)
696
697     @standby_generic 
698     def standby_1(): pass
699     @standby_generic 
700     def standby_2(): pass
701     @standby_generic 
702     def standby_3(): pass
703     @standby_generic 
704     def standby_4(): pass
705     @standby_generic 
706     def standby_5(): pass
707     @standby_generic 
708     def standby_6(): pass
709     @standby_generic 
710     def standby_7(): pass
711     @standby_generic 
712     def standby_8(): pass
713     @standby_generic 
714     def standby_9(): pass
715     @standby_generic 
716     def standby_10(): pass
717     @standby_generic 
718     def standby_11(): pass
719     @standby_generic 
720     def standby_12(): pass
721     @standby_generic 
722     def standby_13(): pass
723     @standby_generic 
724     def standby_14(): pass
725     @standby_generic 
726     def standby_15(): pass
727     @standby_generic 
728     def standby_16(): pass
729     @standby_generic 
730     def standby_17(): pass
731     @standby_generic 
732     def standby_18(): pass
733     @standby_generic 
734     def standby_19(): pass
735     @standby_generic 
736     def standby_20(): pass
737