vserver names based on buildname, rather than the not too helpful rpm name
[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 "%s.%s"%(name,self.vservername)
106         else:
107             return "%s.chroot"%name
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.dirname(sys.argv[0])+"/build"
293         else:
294             # use a standard name - will be relative to remote buildname
295             build_dir="build"
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         if self.options.arch == "i386":
306             personality="-p linux32"
307         else:
308             personality="-p linux64"
309         create_vserver="%s/vtest-init-vserver.sh %s %s %s -- --interface eth0:%s"%\
310             (build_dir,personality,self.vservername,repo_url,self.vserverip)
311         return self.run_in_host(create_vserver) == 0
312
313     def install(self):
314         if self.vserver:
315             return self.install_vserver()
316         else:
317             return self.install_chroot()
318     
319     ### install_rpm - make this an optional step
320     def cache_rpm(self):
321         url = self.options.myplc_url
322         rpm = os.path.basename(url)
323         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()
324         return self.run_in_host(cache_fetch)==0
325
326     def install_rpm_chroot(self):
327         url = self.options.myplc_url
328         rpm = os.path.basename(url)
329         if not self.cache_rpm():
330             return False
331         utils.header('Installing the :  %s'%rpm)
332         return self.run_in_host('rpm -Uvh '+rpm)==0 and self.run_in_host('service plc mount')==0
333
334     def install_rpm_vserver(self):
335         return self.run_in_guest("yum -y install myplc-native")==0
336
337     def install_rpm(self):
338         if self.vserver:
339             return self.install_rpm_vserver()
340         else:
341             return self.install_rpm_chroot()
342
343     ### 
344     def configure(self):
345         tmpname='%s.plc-config-tty'%(self.name())
346         fileconf=open(tmpname,'w')
347         for var in [ 'PLC_NAME',
348                      'PLC_ROOT_PASSWORD',
349                      'PLC_ROOT_USER',
350                      'PLC_MAIL_ENABLED',
351                      'PLC_MAIL_SUPPORT_ADDRESS',
352                      'PLC_DB_HOST',
353                      'PLC_API_HOST',
354                      'PLC_WWW_HOST',
355                      'PLC_BOOT_HOST',
356                      'PLC_NET_DNS1',
357                      'PLC_NET_DNS2']:
358             fileconf.write ('e %s\n%s\n'%(var,self.plc_spec[var]))
359         fileconf.write('w\n')
360         fileconf.write('q\n')
361         fileconf.close()
362         utils.system('cat %s'%tmpname)
363         self.run_in_guest_piped('cat %s'%tmpname,'plc-config-tty')
364         utils.system('rm %s'%tmpname)
365         return True
366
367     # the chroot install is slightly different to this respect
368     def start(self):
369         if self.vserver:
370             self.run_in_guest('service plc start')
371         else:
372             self.run_in_host('service plc start')
373         return True
374         
375     def stop(self):
376         if self.vserver:
377             self.run_in_guest('service plc stop')
378         else:
379             self.run_in_host('service plc stop')
380         return True
381         
382     # could use a TestKey class
383     def store_keys(self):
384         for key_spec in self.plc_spec['keys']:
385                 TestKey(self,key_spec).store_key()
386         return True
387
388     def clean_keys(self):
389         utils.system("rm -rf %s/keys/"%os.path(sys.argv[0]))
390
391     def sites (self):
392         return self.do_sites()
393     
394     def clean_sites (self):
395         return self.do_sites(action="delete")
396     
397     def do_sites (self,action="add"):
398         for site_spec in self.plc_spec['sites']:
399             test_site = TestSite (self,site_spec)
400             if (action != "add"):
401                 utils.header("Deleting site %s in %s"%(test_site.name(),self.name()))
402                 test_site.delete_site()
403                 # deleted with the site
404                 #test_site.delete_users()
405                 continue
406             else:
407                 utils.header("Creating site %s & users in %s"%(test_site.name(),self.name()))
408                 test_site.create_site()
409                 test_site.create_users()
410         return True
411
412     def nodes (self):
413         return self.do_nodes()
414     def clean_nodes (self):
415         return self.do_nodes(action="delete")
416
417     def do_nodes (self,action="add"):
418         for site_spec in self.plc_spec['sites']:
419             test_site = TestSite (self,site_spec)
420             if action != "add":
421                 utils.header("Deleting nodes in site %s"%test_site.name())
422                 for node_spec in site_spec['nodes']:
423                     test_node=TestNode(self,test_site,node_spec)
424                     utils.header("Deleting %s"%test_node.name())
425                     test_node.delete_node()
426             else:
427                 utils.header("Creating nodes for site %s in %s"%(test_site.name(),self.name()))
428                 for node_spec in site_spec['nodes']:
429                     utils.pprint('Creating node %s'%node_spec,node_spec)
430                     test_node = TestNode (self,test_site,node_spec)
431                     test_node.create_node ()
432         return True
433
434     # create nodegroups if needed, and populate
435     # no need for a clean_nodegroups if we are careful enough
436     def nodegroups (self):
437         # 1st pass to scan contents
438         groups_dict = {}
439         for site_spec in self.plc_spec['sites']:
440             test_site = TestSite (self,site_spec)
441             for node_spec in site_spec['nodes']:
442                 test_node=TestNode (self,test_site,node_spec)
443                 if node_spec.has_key('nodegroups'):
444                     nodegroupnames=node_spec['nodegroups']
445                     if isinstance(nodegroupnames,StringTypes):
446                         nodegroupnames = [ nodegroupnames ]
447                     for nodegroupname in nodegroupnames:
448                         if not groups_dict.has_key(nodegroupname):
449                             groups_dict[nodegroupname]=[]
450                         groups_dict[nodegroupname].append(test_node.name())
451         auth=self.auth_root()
452         for (nodegroupname,group_nodes) in groups_dict.iteritems():
453             try:
454                 self.apiserver.GetNodeGroups(auth,{'name':nodegroupname})[0]
455             except:
456                 self.apiserver.AddNodeGroup(auth,{'name':nodegroupname})
457             for node in group_nodes:
458                 self.apiserver.AddNodeToNodeGroup(auth,node,nodegroupname)
459         return True
460
461     def all_hostnames (self) :
462         hostnames = []
463         for site_spec in self.plc_spec['sites']:
464             hostnames += [ node_spec['node_fields']['hostname'] \
465                            for node_spec in site_spec['nodes'] ]
466         return hostnames
467
468     # gracetime : during the first <gracetime> minutes nothing gets printed
469     def do_nodes_booted (self, minutes, gracetime,period=30):
470         if self.options.dry_run:
471             print 'dry_run'
472             return True
473         # compute timeout
474         timeout = datetime.datetime.now()+datetime.timedelta(minutes=minutes)
475         graceout = datetime.datetime.now()+datetime.timedelta(minutes=gracetime)
476         # the nodes that haven't checked yet - start with a full list and shrink over time
477         tocheck = self.all_hostnames()
478         utils.header("checking nodes %r"%tocheck)
479         # create a dict hostname -> status
480         status = dict ( [ (hostname,'undef') for hostname in tocheck ] )
481         while tocheck:
482             # get their status
483             tocheck_status=self.apiserver.GetNodes(self.auth_root(), tocheck, ['hostname','boot_state' ] )
484             # update status
485             for array in tocheck_status:
486                 hostname=array['hostname']
487                 boot_state=array['boot_state']
488                 if boot_state == 'boot':
489                     utils.header ("%s has reached the 'boot' state"%hostname)
490                 else:
491                     # if it's a real node, never mind
492                     (site_spec,node_spec)=self.locate_hostname(hostname)
493                     if TestNode.is_real_model(node_spec['node_fields']['model']):
494                         utils.header("WARNING - Real node %s in %s - ignored"%(hostname,boot_state))
495                         # let's cheat
496                         boot_state = 'boot'
497                     elif datetime.datetime.now() > graceout:
498                         utils.header ("%s still in '%s' state"%(hostname,boot_state))
499                         graceout=datetime.datetime.now()+datetime.timedelta(1)
500                 status[hostname] = boot_state
501             # refresh tocheck
502             tocheck = [ hostname for (hostname,boot_state) in status.iteritems() if boot_state != 'boot' ]
503             if not tocheck:
504                 return True
505             if datetime.datetime.now() > timeout:
506                 for hostname in tocheck:
507                     utils.header("FAILURE due to %s in '%s' state"%(hostname,status[hostname]))
508                 return False
509             # otherwise, sleep for a while
510             time.sleep(period)
511         # only useful in empty plcs
512         return True
513
514     def nodes_booted(self):
515         return self.do_nodes_booted(minutes=20,gracetime=15)
516
517     def do_nodes_ssh(self,minutes,gracetime,period=30):
518         # compute timeout
519         timeout = datetime.datetime.now()+datetime.timedelta(minutes=minutes)
520         graceout = datetime.datetime.now()+datetime.timedelta(minutes=gracetime)
521         tocheck = self.all_hostnames()
522 #        self.scan_publicKeys(tocheck)
523         utils.header("checking Connectivity on nodes %r"%tocheck)
524         while tocheck:
525             for hostname in tocheck:
526                 # try to ssh in nodes
527                 node_test_ssh = TestSsh (hostname,key="/etc/planetlab/root_ssh_key.rsa")
528                 success=self.run_in_guest(node_test_ssh.actual_command("hostname"))==0
529                 if success:
530                     utils.header('The node %s is sshable -->'%hostname)
531                     # refresh tocheck
532                     tocheck.remove(hostname)
533                 else:
534                     # we will have tried real nodes once, in case they're up - but if not, just skip
535                     (site_spec,node_spec)=self.locate_hostname(hostname)
536                     if TestNode.is_real_model(node_spec['node_fields']['model']):
537                         utils.header ("WARNING : check ssh access into real node %s - skipped"%hostname)
538                         tocheck.remove(hostname)
539                     elif datetime.datetime.now() > graceout:
540                         utils.header("Could not ssh-enter root context on %s"%hostname)
541             if  not tocheck:
542                 return True
543             if datetime.datetime.now() > timeout:
544                 for hostname in tocheck:
545                     utils.header("FAILURE to ssh into %s"%hostname)
546                 return False
547             # otherwise, sleep for a while
548             time.sleep(period)
549         # only useful in empty plcs
550         return True
551         
552     def nodes_ssh(self):
553         return self.do_nodes_ssh(minutes=6,gracetime=4)
554     
555     @node_mapper
556     def init_node (self): pass
557     @node_mapper
558     def bootcd (self): pass
559     @node_mapper
560     def configure_qemu (self): pass
561     @node_mapper
562     def reinstall_node (self): pass
563     @node_mapper
564     def export_qemu (self): pass
565         
566     def do_check_initscripts(self):
567         overall = True
568         for slice_spec in self.plc_spec['slices']:
569             if not slice_spec.has_key('initscriptname'):
570                 continue
571             initscript=slice_spec['initscriptname']
572             for nodename in slice_spec['nodenames']:
573                 (site,node) = self.locate_node (nodename)
574                 # xxx - passing the wrong site - probably harmless
575                 test_site = TestSite (self,site)
576                 test_slice = TestSlice (self,test_site,slice_spec)
577                 test_node = TestNode (self,test_site,node)
578                 test_sliver = TestSliver (self, test_node, test_slice)
579                 if not test_sliver.check_initscript(initscript):
580                     overall = False
581         return overall
582             
583     def check_initscripts(self):
584             return self.do_check_initscripts()
585                     
586     def initscripts (self):
587         for initscript in self.plc_spec['initscripts']:
588             utils.pprint('Adding Initscript in plc %s'%self.plc_spec['name'],initscript)
589             self.apiserver.AddInitScript(self.auth_root(),initscript['initscript_fields'])
590         return True
591
592     def slices (self):
593         return self.do_slices()
594
595     def clean_slices (self):
596         return self.do_slices("delete")
597
598     def do_slices (self,  action="add"):
599         for slice in self.plc_spec['slices']:
600             site_spec = self.locate_site (slice['sitename'])
601             test_site = TestSite(self,site_spec)
602             test_slice=TestSlice(self,test_site,slice)
603             if action != "add":
604                 utils.header("Deleting slices in site %s"%test_site.name())
605                 test_slice.delete_slice()
606             else:    
607                 utils.pprint("Creating slice",slice)
608                 test_slice.create_slice()
609                 utils.header('Created Slice %s'%slice['slice_fields']['name'])
610         return True
611         
612     @slice_mapper_options
613     def check_slice(self): pass
614
615     @node_mapper
616     def clear_known_hosts (self): pass
617     
618     @node_mapper
619     def start_node (self) : pass
620
621     def all_sliver_objs (self):
622         result=[]
623         for slice_spec in self.plc_spec['slices']:
624             slicename = slice_spec['slice_fields']['name']
625             for nodename in slice_spec['nodenames']:
626                 result.append(self.locate_sliver_obj (nodename,slicename))
627         return result
628
629     def locate_sliver_obj (self,nodename,slicename):
630         (site,node) = self.locate_node(nodename)
631         slice = self.locate_slice (slicename)
632         # build objects
633         test_site = TestSite (self, site)
634         test_node = TestNode (self, test_site,node)
635         # xxx the slice site is assumed to be the node site - mhh - probably harmless
636         test_slice = TestSlice (self, test_site, slice)
637         return TestSliver (self, test_node, test_slice)
638
639     def check_tcp (self):
640         specs = self.plc_spec['tcp_test']
641         overall=True
642         for spec in specs:
643             port = spec['port']
644             # server side
645             s_test_sliver = self.locate_sliver_obj (spec['server_node'],spec['server_slice'])
646             if not s_test_sliver.run_tcp_server(port,timeout=10):
647                 overall=False
648                 break
649
650             # idem for the client side
651             c_test_sliver = self.locate_sliver_obj(spec['server_node'],spec['server_slice'])
652             if not c_test_sliver.run_tcp_client(s_test_sliver.test_node.name(),port):
653                 overall=False
654         return overall
655     
656
657     def gather_logs (self):
658         # (1) get the plc's /var/log and store it locally in logs/myplc.var-log.<plcname>/*
659         # (2) get all the nodes qemu log and store it as logs/node.qemu.<node>.log
660         # (3) get the nodes /var/log and store is as logs/node.var-log.<node>/*
661         # (4) as far as possible get the slice's /var/log as logs/sliver.var-log.<sliver>/*
662         # (1)
663         print "-------------------- TestPlc.gather_logs : PLC's /var/log"
664         self.gather_var_logs ()
665         # (2) 
666         print "-------------------- TestPlc.gather_logs : nodes's QEMU logs"
667         for site_spec in self.plc_spec['sites']:
668             test_site = TestSite (self,site_spec)
669             for node_spec in site_spec['nodes']:
670                 test_node=TestNode(self,test_site,node_spec)
671                 test_node.gather_qemu_logs()
672         # (3)
673         print "-------------------- TestPlc.gather_logs : nodes's /var/log"
674         self.gather_nodes_var_logs()
675         # (4)
676         print "-------------------- TestPlc.gather_logs : sample sliver's /var/log"
677         self.gather_slivers_var_logs()
678         return True
679
680     def gather_slivers_var_logs(self):
681         for test_sliver in self.all_sliver_objs():
682             remote = test_sliver.tar_var_logs()
683             utils.system("mkdir -p logs/sliver.var-log.%s"%test_sliver.name())
684             command = remote + " | tar -C logs/sliver.var-log.%s -xf -"%test_sliver.name()
685             utils.system(command)
686         return True
687
688     def gather_var_logs (self):
689         to_plc = self.actual_command_in_guest("tar -C /var/log/ -cf - .")        
690         command = to_plc + "| tar -C logs/myplc.var-log.%s -xf -"%self.name()
691         utils.system("mkdir -p logs/myplc.var-log.%s"%self.name())
692         utils.system(command)
693
694     def gather_nodes_var_logs (self):
695         for site_spec in self.plc_spec['sites']:
696             test_site = TestSite (self,site_spec)
697             for node_spec in site_spec['nodes']:
698                 test_node=TestNode(self,test_site,node_spec)
699                 test_ssh = TestSsh (test_node.name(),key="/etc/planetlab/root_ssh_key.rsa")
700                 to_plc = self.actual_command_in_guest ( test_ssh.actual_command("tar -C /var/log -cf - ."))
701                 command = to_plc + "| tar -C logs/node.var-log.%s -xf -"%test_node.name()
702                 utils.system("mkdir -p logs/node.var-log.%s"%test_node.name())
703                 utils.system(command)
704
705
706     # returns the filename to use for sql dump/restore, using options.dbname if set
707     def dbfile (self, database):
708         # uses options.dbname if it is found
709         try:
710             name=self.options.dbname
711             if not isinstance(name,StringTypes):
712                 raise Exception
713         except:
714             t=datetime.datetime.now()
715             d=t.date()
716             name=str(d)
717         return "/root/%s-%s.sql"%(database,name)
718
719     def db_dump(self):
720         dump=self.dbfile("planetab4")
721         self.run_in_guest('pg_dump -U pgsqluser planetlab4 -f '+ dump)
722         utils.header('Dumped planetlab4 database in %s'%dump)
723         return True
724
725     def db_restore(self):
726         dump=self.dbfile("planetab4")
727         ##stop httpd service
728         self.run_in_guest('service httpd stop')
729         # xxx - need another wrapper
730         self.run_in_guest_piped('echo drop database planetlab4','psql --user=pgsqluser template1')
731         self.run_in_guest('createdb -U postgres --encoding=UNICODE --owner=pgsqluser planetlab4')
732         self.run_in_guest('psql -U pgsqluser planetlab4 -f '+dump)
733         ##starting httpd service
734         self.run_in_guest('service httpd start')
735
736         utils.header('Database restored from ' + dump)
737
738     @standby_generic 
739     def standby_1(): pass
740     @standby_generic 
741     def standby_2(): pass
742     @standby_generic 
743     def standby_3(): pass
744     @standby_generic 
745     def standby_4(): pass
746     @standby_generic 
747     def standby_5(): pass
748     @standby_generic 
749     def standby_6(): pass
750     @standby_generic 
751     def standby_7(): pass
752     @standby_generic 
753     def standby_8(): pass
754     @standby_generic 
755     def standby_9(): pass
756     @standby_generic 
757     def standby_10(): pass
758     @standby_generic 
759     def standby_11(): pass
760     @standby_generic 
761     def standby_12(): pass
762     @standby_generic 
763     def standby_13(): pass
764     @standby_generic 
765     def standby_14(): pass
766     @standby_generic 
767     def standby_15(): pass
768     @standby_generic 
769     def standby_16(): pass
770     @standby_generic 
771     def standby_17(): pass
772     @standby_generic 
773     def standby_18(): pass
774     @standby_generic 
775     def standby_19(): pass
776     @standby_generic 
777     def standby_20(): pass
778