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