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