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