eb5c9e3d5098a644af6d8267f7615e7bc3327868
[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 from TestSliceSfa import TestSliceSfa
21 from TestUserSfa import TestUserSfa
22
23 # step methods must take (self) and return a boolean (options is a member of the class)
24
25 def standby(minutes,dry_run):
26     utils.header('Entering StandBy for %d mn'%minutes)
27     if dry_run:
28         print 'dry_run'
29     else:
30         time.sleep(60*minutes)
31     return True
32
33 def standby_generic (func):
34     def actual(self):
35         minutes=int(func.__name__.split("_")[1])
36         return standby(minutes,self.options.dry_run)
37     return actual
38
39 def node_mapper (method):
40     def actual(self):
41         overall=True
42         node_method = TestNode.__dict__[method.__name__]
43         for site_spec in self.plc_spec['sites']:
44             test_site = TestSite (self,site_spec)
45             for node_spec in site_spec['nodes']:
46                 test_node = TestNode (self,test_site,node_spec)
47                 if not node_method(test_node): overall=False
48         return overall
49     # restore the doc text
50     actual.__doc__=method.__doc__
51     return actual
52
53 def slice_mapper_options (method):
54     def actual(self):
55         overall=True
56         slice_method = TestSlice.__dict__[method.__name__]
57         for slice_spec in self.plc_spec['slices']:
58             site_spec = self.locate_site (slice_spec['sitename'])
59             test_site = TestSite(self,site_spec)
60             test_slice=TestSlice(self,test_site,slice_spec)
61             if not slice_method(test_slice,self.options): overall=False
62         return overall
63     # restore the doc text
64     actual.__doc__=method.__doc__
65     return actual
66
67 def slice_mapper_options_sfa (method):
68     def actual(self):
69         test_plc=self
70         overall=True
71         slice_method = TestSliceSfa.__dict__[method.__name__]
72         for slice_spec in self.plc_spec['sfa']['slices_sfa']:
73             site_spec = self.locate_site (slice_spec['sitename'])
74             test_site = TestSite(self,site_spec)
75             test_slice=TestSliceSfa(test_plc,test_site,slice_spec)
76             if not slice_method(test_slice,self.options): overall=False
77         return overall
78     # restore the doc text
79     actual.__doc__=method.__doc__
80     return actual
81
82 SEP='<sep>'
83
84 class TestPlc:
85
86     default_steps = [
87         'display', 'resources_pre', SEP,
88         'delete_vs','create_vs','install', 'configure', 'start', SEP,
89         'fetch_keys', 'store_keys', 'clear_known_hosts', SEP,
90         'initscripts', 'sites', 'nodes', 'slices', 'nodegroups', SEP,
91         'reinstall_node', 'init_node','bootcd', 'configure_qemu', 'export_qemu',
92         'kill_all_qemus', 'start_node', SEP,
93         # better use of time: do this now that the nodes are taking off
94         'plcsh_stress_test', SEP,
95         'install_sfa', 'configure_sfa', 'import_sfa', 'start_sfa', SEP,
96         'setup_sfa', 'add_sfa', 'update_sfa', 'view_sfa', SEP,
97         'nodes_ssh_debug', 'nodes_ssh_boot', 'check_slice', 'check_initscripts', SEP,
98         # optionally run sfa later; takes longer, but checks more about nm 
99         # 'install_sfa', 'configure_sfa', 'import_sfa', 'start_sfa', SEP,
100         # 'setup_sfa', 'add_sfa', 'update_sfa', 'view_sfa', SEP,
101         'check_slice_sfa', 'delete_sfa', 'stop_sfa', SEP,
102         'check_tcp',  'check_hooks',  SEP,
103         'force_gather_logs', 'force_resources_post',
104         ]
105     other_steps = [ 
106         'show_boxes', 'resources_list','resources_release','resources_release_plc','resources_release_qemu',SEP,
107         'stop', 'vs_start', SEP,
108         'clean_initscripts', 'clean_nodegroups','clean_all_sites', SEP,
109         'clean_sites', 'clean_nodes', 'clean_slices', 'clean_keys', SEP,
110         'populate' , SEP,
111         'list_all_qemus', 'list_qemus', 'kill_qemus', SEP,
112         'db_dump' , 'db_restore', SEP,
113         'standby_1 through 20',
114         ]
115
116     @staticmethod
117     def printable_steps (list):
118         return " ".join(list).replace(" "+SEP+" "," \\\n")
119     @staticmethod
120     def valid_step (step):
121         return step != SEP
122
123     def __init__ (self,plc_spec,options):
124         self.plc_spec=plc_spec
125         self.options=options
126         self.test_ssh=TestSsh(self.plc_spec['hostname'],self.options.buildname)
127         try:
128             self.vserverip=plc_spec['vserverip']
129             self.vservername=plc_spec['vservername']
130             self.url="https://%s:443/PLCAPI/"%plc_spec['vserverip']
131             self.vserver=True
132         except:
133             raise Exception,'chroot-based myplc testing is deprecated'
134         self.apiserver=TestApiserver(self.url,options.dry_run)
135         
136     def name(self):
137         name=self.plc_spec['name']
138         return "%s.%s"%(name,self.vservername)
139
140     def hostname(self):
141         return self.plc_spec['hostname']
142
143     def is_local (self):
144         return self.test_ssh.is_local()
145
146     # define the API methods on this object through xmlrpc
147     # would help, but not strictly necessary
148     def connect (self):
149         pass
150
151     def actual_command_in_guest (self,command):
152         return self.test_ssh.actual_command(self.host_to_guest(command))
153     
154     def start_guest (self):
155       return utils.system(self.test_ssh.actual_command(self.start_guest_in_host()))
156     
157     def run_in_guest (self,command):
158         return utils.system(self.actual_command_in_guest(command))
159     
160     def run_in_host (self,command):
161         return self.test_ssh.run_in_buildname(command)
162
163     #command gets run in the vserver
164     def host_to_guest(self,command):
165         return "vserver %s exec %s"%(self.vservername,command)
166     
167     #command gets run in the vserver
168     def start_guest_in_host(self):
169         return "vserver %s start"%(self.vservername)
170     
171     # xxx quick n dirty
172     def run_in_guest_piped (self,local,remote):
173         return utils.system(local+" | "+self.test_ssh.actual_command(self.host_to_guest(remote),keep_stdin=True))
174
175     def auth_root (self):
176         return {'Username':self.plc_spec['PLC_ROOT_USER'],
177                 'AuthMethod':'password',
178                 'AuthString':self.plc_spec['PLC_ROOT_PASSWORD'],
179                 'Role' : self.plc_spec['role']
180                 }
181     def locate_site (self,sitename):
182         for site in self.plc_spec['sites']:
183             if site['site_fields']['name'] == sitename:
184                 return site
185             if site['site_fields']['login_base'] == sitename:
186                 return site
187         raise Exception,"Cannot locate site %s"%sitename
188         
189     def locate_node (self,nodename):
190         for site in self.plc_spec['sites']:
191             for node in site['nodes']:
192                 if node['name'] == nodename:
193                     return (site,node)
194         raise Exception,"Cannot locate node %s"%nodename
195         
196     def locate_hostname (self,hostname):
197         for site in self.plc_spec['sites']:
198             for node in site['nodes']:
199                 if node['node_fields']['hostname'] == hostname:
200                     return (site,node)
201         raise Exception,"Cannot locate hostname %s"%hostname
202         
203     def locate_key (self,keyname):
204         for key in self.plc_spec['keys']:
205             if key['name'] == keyname:
206                 return key
207         raise Exception,"Cannot locate key %s"%keyname
208
209     def locate_slice (self, slicename):
210         for slice in self.plc_spec['slices']:
211             if slice['slice_fields']['name'] == slicename:
212                 return slice
213         raise Exception,"Cannot locate slice %s"%slicename
214
215     def all_sliver_objs (self):
216         result=[]
217         for slice_spec in self.plc_spec['slices']:
218             slicename = slice_spec['slice_fields']['name']
219             for nodename in slice_spec['nodenames']:
220                 result.append(self.locate_sliver_obj (nodename,slicename))
221         return result
222
223     def locate_sliver_obj (self,nodename,slicename):
224         (site,node) = self.locate_node(nodename)
225         slice = self.locate_slice (slicename)
226         # build objects
227         test_site = TestSite (self, site)
228         test_node = TestNode (self, test_site,node)
229         # xxx the slice site is assumed to be the node site - mhh - probably harmless
230         test_slice = TestSlice (self, test_site, slice)
231         return TestSliver (self, test_node, test_slice)
232
233     def locate_first_node(self):
234         nodename=self.plc_spec['slices'][0]['nodenames'][0]
235         (site,node) = self.locate_node(nodename)
236         test_site = TestSite (self, site)
237         test_node = TestNode (self, test_site,node)
238         return test_node
239
240     def locate_first_sliver (self):
241         slice_spec=self.plc_spec['slices'][0]
242         slicename=slice_spec['slice_fields']['name']
243         nodename=slice_spec['nodenames'][0]
244         return self.locate_sliver_obj(nodename,slicename)
245
246     # all different hostboxes used in this plc
247     def gather_hostBoxes(self):
248         # maps on sites and nodes, return [ (host_box,test_node) ]
249         tuples=[]
250         for site_spec in self.plc_spec['sites']:
251             test_site = TestSite (self,site_spec)
252             for node_spec in site_spec['nodes']:
253                 test_node = TestNode (self, test_site, node_spec)
254                 if not test_node.is_real():
255                     tuples.append( (test_node.host_box(),test_node) )
256         # transform into a dict { 'host_box' -> [ test_node .. ] }
257         result = {}
258         for (box,node) in tuples:
259             if not result.has_key(box):
260                 result[box]=[node]
261             else:
262                 result[box].append(node)
263         return result
264                     
265     # a step for checking this stuff
266     def show_boxes (self):
267         'print summary of nodes location'
268         for (box,nodes) in self.gather_hostBoxes().iteritems():
269             print box,":"," + ".join( [ node.name() for node in nodes ] )
270         return True
271
272     # make this a valid step
273     def kill_all_qemus(self):
274         'kill all qemu instances on the qemu boxes involved by this setup'
275         # this is the brute force version, kill all qemus on that host box
276         for (box,nodes) in self.gather_hostBoxes().iteritems():
277             # pass the first nodename, as we don't push template-qemu on testboxes
278             nodedir=nodes[0].nodedir()
279             TestBox(box,self.options.buildname).kill_all_qemus(nodedir)
280         return True
281
282     # make this a valid step
283     def list_all_qemus(self):
284         'list all qemu instances on the qemu boxes involved by this setup'
285         for (box,nodes) in self.gather_hostBoxes().iteritems():
286             # this is the brute force version, kill all qemus on that host box
287             TestBox(box,self.options.buildname).list_all_qemus()
288         return True
289
290     # kill only the right qemus
291     def list_qemus(self):
292         'list qemu instances for our nodes'
293         for (box,nodes) in self.gather_hostBoxes().iteritems():
294             # the fine-grain version
295             for node in nodes:
296                 node.list_qemu()
297         return True
298
299     # kill only the right qemus
300     def kill_qemus(self):
301         'kill the qemu instances for our nodes'
302         for (box,nodes) in self.gather_hostBoxes().iteritems():
303             # the fine-grain version
304             for node in nodes:
305                 node.kill_qemu()
306         return True
307
308     #################### display config
309     def display (self):
310         "show test configuration after localization"
311         self.display_pass (1)
312         self.display_pass (2)
313         return True
314
315     # entry point
316     always_display_keys=['PLC_WWW_HOST','nodes','sites',]
317     def display_pass (self,passno):
318         for (key,val) in self.plc_spec.iteritems():
319             if not self.options.verbose and key not in TestPlc.always_display_keys: continue
320             if passno == 2:
321                 if key == 'sites':
322                     for site in val:
323                         self.display_site_spec(site)
324                         for node in site['nodes']:
325                             self.display_node_spec(node)
326                 elif key=='initscripts':
327                     for initscript in val:
328                         self.display_initscript_spec (initscript)
329                 elif key=='slices':
330                     for slice in val:
331                         self.display_slice_spec (slice)
332                 elif key=='keys':
333                     for key in val:
334                         self.display_key_spec (key)
335             elif passno == 1:
336                 if key not in ['sites','initscripts','slices','keys', 'sfa']:
337                     print '+   ',key,':',val
338
339     def display_site_spec (self,site):
340         print '+ ======== site',site['site_fields']['name']
341         for (k,v) in site.iteritems():
342             if not self.options.verbose and k not in TestPlc.always_display_keys: continue
343             if k=='nodes':
344                 if v: 
345                     print '+       ','nodes : ',
346                     for node in v:  
347                         print node['node_fields']['hostname'],'',
348                     print ''
349             elif k=='users':
350                 if v: 
351                     print '+       users : ',
352                     for user in v:  
353                         print user['name'],'',
354                     print ''
355             elif k == 'site_fields':
356                 print '+       login_base',':',v['login_base']
357             elif k == 'address_fields':
358                 pass
359             else:
360                 print '+       ',k,
361                 PrettyPrinter(indent=8,depth=2).pprint(v)
362         
363     def display_initscript_spec (self,initscript):
364         print '+ ======== initscript',initscript['initscript_fields']['name']
365
366     def display_key_spec (self,key):
367         print '+ ======== key',key['name']
368
369     def display_slice_spec (self,slice):
370         print '+ ======== slice',slice['slice_fields']['name']
371         for (k,v) in slice.iteritems():
372             if k=='nodenames':
373                 if v: 
374                     print '+       nodes : ',
375                     for nodename in v:  
376                         print nodename,'',
377                     print ''
378             elif k=='usernames':
379                 if v: 
380                     print '+       users : ',
381                     for username in v:  
382                         print username,'',
383                     print ''
384             elif k=='slice_fields':
385                 print '+       fields',':',
386                 print 'max_nodes=',v['max_nodes'],
387                 print ''
388             else:
389                 print '+       ',k,v
390
391     def display_node_spec (self,node):
392         print "+           node",node['name'],"host_box=",node['host_box'],
393         print "hostname=",node['node_fields']['hostname'],
394         print "ip=",node['interface_fields']['ip']
395     
396
397     # another entry point for just showing the boxes involved
398     def display_mapping (self):
399         TestPlc.display_mapping_plc(self.plc_spec)
400         return True
401
402     @staticmethod
403     def display_mapping_plc (plc_spec):
404         print '+ MyPLC',plc_spec['name']
405         print '+\tvserver address = root@%s:/vservers/%s'%(plc_spec['hostname'],plc_spec['vservername'])
406         print '+\tIP = %s/%s'%(plc_spec['PLC_API_HOST'],plc_spec['vserverip'])
407         for site_spec in plc_spec['sites']:
408             for node_spec in site_spec['nodes']:
409                 TestPlc.display_mapping_node(node_spec)
410
411     @staticmethod
412     def display_mapping_node (node_spec):
413         print '+   NODE %s'%(node_spec['name'])
414         print '+\tqemu box %s'%node_spec['host_box']
415         print '+\thostname=%s'%node_spec['node_fields']['hostname']
416
417     def resources_pre (self):
418         "run site-dependant pre-test script as defined in LocalTestResources"
419         from LocalTestResources import local_resources
420         return local_resources.step_pre(self)
421  
422     def resources_post (self):
423         "run site-dependant post-test script as defined in LocalTestResources"
424         from LocalTestResources import local_resources
425         return local_resources.step_post(self)
426  
427     def resources_list (self):
428         "run site-dependant list script as defined in LocalTestResources"
429         from LocalTestResources import local_resources
430         return local_resources.step_list(self)
431  
432     def resources_release (self):
433         "run site-dependant release script as defined in LocalTestResources"
434         from LocalTestResources import local_resources
435         return local_resources.step_release(self)
436  
437     def resources_release_plc (self):
438         "run site-dependant release script as defined in LocalTestResources"
439         from LocalTestResources import local_resources
440         return local_resources.step_release_plc(self)
441  
442     def resources_release_qemu (self):
443         "run site-dependant release script as defined in LocalTestResources"
444         from LocalTestResources import local_resources
445         return local_resources.step_release_qemu(self)
446  
447     def delete_vs(self):
448         "vserver delete the test myplc"
449         self.run_in_host("vserver --silent %s delete"%self.vservername)
450         return True
451
452     ### install
453     # historically the build was being fetched by the tests
454     # now the build pushes itself as a subdir of the tests workdir
455     # so that the tests do not have to worry about extracting the build (svn, git, or whatever)
456     def create_vs (self):
457         "vserver creation (no install done)"
458         # push the local build/ dir to the testplc box 
459         if self.is_local():
460             # a full path for the local calls
461             build_dir=os.path.dirname(sys.argv[0])
462             # sometimes this is empty - set to "." in such a case
463             if not build_dir: build_dir="."
464             build_dir += "/build"
465         else:
466             # use a standard name - will be relative to remote buildname
467             build_dir="build"
468             # remove for safety; do *not* mkdir first, otherwise we end up with build/build/
469             self.test_ssh.rmdir(build_dir)
470             self.test_ssh.copy(build_dir,recursive=True)
471         # the repo url is taken from arch-rpms-url 
472         # with the last step (i386) removed
473         repo_url = self.options.arch_rpms_url
474         for level in [ 'arch' ]:
475             repo_url = os.path.dirname(repo_url)
476         # pass the vbuild-nightly options to vtest-init-vserver
477         test_env_options=""
478         test_env_options += " -p %s"%self.options.personality
479         test_env_options += " -d %s"%self.options.pldistro
480         test_env_options += " -f %s"%self.options.fcdistro
481         script="vtest-init-vserver.sh"
482         vserver_name = self.vservername
483         vserver_options="--netdev eth0 --interface %s"%self.vserverip
484         try:
485             vserver_hostname=socket.gethostbyaddr(self.vserverip)[0]
486             vserver_options += " --hostname %s"%vserver_hostname
487         except:
488             print "Cannot reverse lookup %s"%self.vserverip
489             print "This is considered fatal, as this might pollute the test results"
490             return False
491         create_vserver="%(build_dir)s/%(script)s %(test_env_options)s %(vserver_name)s %(repo_url)s -- %(vserver_options)s"%locals()
492         return self.run_in_host(create_vserver) == 0
493
494     ### install_rpm 
495     def install(self):
496         "yum install myplc, noderepo, and the plain bootstrapfs"
497
498         # workaround for getting pgsql8.2 on centos5
499         if self.options.fcdistro == "centos5":
500             self.run_in_guest("rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-3.noarch.rpm")
501
502         if self.options.personality == "linux32":
503             arch = "i386"
504         elif self.options.personality == "linux64":
505             arch = "x86_64"
506         else:
507             raise Exception, "Unsupported personality %r"%self.options.personality
508         
509         nodefamily="%s-%s-%s"%(self.options.pldistro,self.options.fcdistro,arch)
510
511         # try to install slicerepo - not fatal yet
512         self.run_in_guest("yum -y install slicerepo-%s"%nodefamily)
513         
514         return \
515             self.run_in_guest("yum -y install myplc")==0 and \
516             self.run_in_guest("yum -y install noderepo-%s"%nodefamily)==0 and \
517             self.run_in_guest("yum -y install bootstrapfs-%s-plain"%nodefamily)==0 
518
519     ### 
520     def configure(self):
521         "run plc-config-tty"
522         tmpname='%s.plc-config-tty'%(self.name())
523         fileconf=open(tmpname,'w')
524         for var in [ 'PLC_NAME',
525                      'PLC_ROOT_PASSWORD',
526                      'PLC_ROOT_USER',
527                      'PLC_MAIL_ENABLED',
528                      'PLC_MAIL_SUPPORT_ADDRESS',
529                      'PLC_DB_HOST',
530                      'PLC_DB_PASSWORD',
531                      # Above line was added for integrating SFA Testing
532                      'PLC_API_HOST',
533                      'PLC_WWW_HOST',
534                      'PLC_BOOT_HOST',
535                      'PLC_NET_DNS1',
536                      'PLC_NET_DNS2']:
537             fileconf.write ('e %s\n%s\n'%(var,self.plc_spec[var]))
538         fileconf.write('w\n')
539         fileconf.write('q\n')
540         fileconf.close()
541         utils.system('cat %s'%tmpname)
542         self.run_in_guest_piped('cat %s'%tmpname,'plc-config-tty')
543         utils.system('rm %s'%tmpname)
544         return True
545
546     def start(self):
547         "service plc start"
548         self.run_in_guest('service plc start')
549         return True
550
551     def stop(self):
552         "service plc stop"
553         self.run_in_guest('service plc stop')
554         return True
555         
556     def vs_start (self):
557         "start the PLC vserver"
558         self.start_guest()
559         return True
560
561     # stores the keys from the config for further use
562     def store_keys(self):
563         "stores test users ssh keys in keys/"
564         for key_spec in self.plc_spec['keys']:
565                 TestKey(self,key_spec).store_key()
566         return True
567
568     def clean_keys(self):
569         "removes keys cached in keys/"
570         utils.system("rm -rf %s/keys/"%os.path(sys.argv[0]))
571
572     # fetches the ssh keys in the plc's /etc/planetlab and stores them in keys/
573     # for later direct access to the nodes
574     def fetch_keys(self):
575         "gets ssh keys in /etc/planetlab/ and stores them locally in keys/"
576         dir="./keys"
577         if not os.path.isdir(dir):
578             os.mkdir(dir)
579         vservername=self.vservername
580         overall=True
581         prefix = 'debug_ssh_key'
582         for ext in [ 'pub', 'rsa' ] :
583             src="/vservers/%(vservername)s/etc/planetlab/%(prefix)s.%(ext)s"%locals()
584             dst="keys/%(vservername)s-debug.%(ext)s"%locals()
585             if self.test_ssh.fetch(src,dst) != 0: overall=False
586         return overall
587
588     def sites (self):
589         "create sites with PLCAPI"
590         return self.do_sites()
591     
592     def clean_sites (self):
593         "delete sites with PLCAPI"
594         return self.do_sites(action="delete")
595     
596     def do_sites (self,action="add"):
597         for site_spec in self.plc_spec['sites']:
598             test_site = TestSite (self,site_spec)
599             if (action != "add"):
600                 utils.header("Deleting site %s in %s"%(test_site.name(),self.name()))
601                 test_site.delete_site()
602                 # deleted with the site
603                 #test_site.delete_users()
604                 continue
605             else:
606                 utils.header("Creating site %s & users in %s"%(test_site.name(),self.name()))
607                 test_site.create_site()
608                 test_site.create_users()
609         return True
610
611     def clean_all_sites (self):
612         "Delete all sites in PLC, and related objects"
613         print 'auth_root',self.auth_root()
614         site_ids = [s['site_id'] for s in self.apiserver.GetSites(self.auth_root(), {}, ['site_id'])]
615         for site_id in site_ids:
616             print 'Deleting site_id',site_id
617             self.apiserver.DeleteSite(self.auth_root(),site_id)
618
619     def nodes (self):
620         "create nodes with PLCAPI"
621         return self.do_nodes()
622     def clean_nodes (self):
623         "delete nodes with PLCAPI"
624         return self.do_nodes(action="delete")
625
626     def do_nodes (self,action="add"):
627         for site_spec in self.plc_spec['sites']:
628             test_site = TestSite (self,site_spec)
629             if action != "add":
630                 utils.header("Deleting nodes in site %s"%test_site.name())
631                 for node_spec in site_spec['nodes']:
632                     test_node=TestNode(self,test_site,node_spec)
633                     utils.header("Deleting %s"%test_node.name())
634                     test_node.delete_node()
635             else:
636                 utils.header("Creating nodes for site %s in %s"%(test_site.name(),self.name()))
637                 for node_spec in site_spec['nodes']:
638                     utils.pprint('Creating node %s'%node_spec,node_spec)
639                     test_node = TestNode (self,test_site,node_spec)
640                     test_node.create_node ()
641         return True
642
643     def nodegroups (self):
644         "create nodegroups with PLCAPI"
645         return self.do_nodegroups("add")
646     def clean_nodegroups (self):
647         "delete nodegroups with PLCAPI"
648         return self.do_nodegroups("delete")
649
650     # create nodegroups if needed, and populate
651     def do_nodegroups (self, action="add"):
652         # 1st pass to scan contents
653         groups_dict = {}
654         for site_spec in self.plc_spec['sites']:
655             test_site = TestSite (self,site_spec)
656             for node_spec in site_spec['nodes']:
657                 test_node=TestNode (self,test_site,node_spec)
658                 if node_spec.has_key('nodegroups'):
659                     nodegroupnames=node_spec['nodegroups']
660                     if isinstance(nodegroupnames,StringTypes):
661                         nodegroupnames = [ nodegroupnames ]
662                     for nodegroupname in nodegroupnames:
663                         if not groups_dict.has_key(nodegroupname):
664                             groups_dict[nodegroupname]=[]
665                         groups_dict[nodegroupname].append(test_node.name())
666         auth=self.auth_root()
667         overall = True
668         for (nodegroupname,group_nodes) in groups_dict.iteritems():
669             if action == "add":
670                 print 'nodegroups:','dealing with nodegroup',nodegroupname,'on nodes',group_nodes
671                 # first, check if the nodetagtype is here
672                 tag_types = self.apiserver.GetTagTypes(auth,{'tagname':nodegroupname})
673                 if tag_types:
674                     tag_type_id = tag_types[0]['tag_type_id']
675                 else:
676                     tag_type_id = self.apiserver.AddTagType(auth,
677                                                             {'tagname':nodegroupname,
678                                                              'description': 'for nodegroup %s'%nodegroupname,
679                                                              'category':'test',
680                                                              'min_role_id':10})
681                 print 'located tag (type)',nodegroupname,'as',tag_type_id
682                 # create nodegroup
683                 nodegroups = self.apiserver.GetNodeGroups (auth, {'groupname':nodegroupname})
684                 if not nodegroups:
685                     self.apiserver.AddNodeGroup(auth, nodegroupname, tag_type_id, 'yes')
686                     print 'created nodegroup',nodegroupname,'from tagname',nodegroupname,'and value','yes'
687                 # set node tag on all nodes, value='yes'
688                 for nodename in group_nodes:
689                     try:
690                         self.apiserver.AddNodeTag(auth, nodename, nodegroupname, "yes")
691                     except:
692                         traceback.print_exc()
693                         print 'node',nodename,'seems to already have tag',nodegroupname
694                     # check anyway
695                     try:
696                         expect_yes = self.apiserver.GetNodeTags(auth,
697                                                                 {'hostname':nodename,
698                                                                  'tagname':nodegroupname},
699                                                                 ['value'])[0]['value']
700                         if expect_yes != "yes":
701                             print 'Mismatch node tag on node',nodename,'got',expect_yes
702                             overall=False
703                     except:
704                         if not self.options.dry_run:
705                             print 'Cannot find tag',nodegroupname,'on node',nodename
706                             overall = False
707             else:
708                 try:
709                     print 'cleaning nodegroup',nodegroupname
710                     self.apiserver.DeleteNodeGroup(auth,nodegroupname)
711                 except:
712                     traceback.print_exc()
713                     overall=False
714         return overall
715
716     # return a list of tuples (nodename,qemuname)
717     def all_node_infos (self) :
718         node_infos = []
719         for site_spec in self.plc_spec['sites']:
720             node_infos += [ (node_spec['node_fields']['hostname'],node_spec['host_box']) \
721                            for node_spec in site_spec['nodes'] ]
722         return node_infos
723     
724     def all_nodenames (self): return [ x[0] for x in self.all_node_infos() ]
725
726     # silent_minutes : during the first <silent_minutes> minutes nothing gets printed
727     def nodes_check_boot_state (self, target_boot_state, timeout_minutes, silent_minutes,period=15):
728         if self.options.dry_run:
729             print 'dry_run'
730             return True
731         # compute timeout
732         timeout = datetime.datetime.now()+datetime.timedelta(minutes=timeout_minutes)
733         graceout = datetime.datetime.now()+datetime.timedelta(minutes=silent_minutes)
734         # the nodes that haven't checked yet - start with a full list and shrink over time
735         tocheck = self.all_hostnames()
736         utils.header("checking nodes %r"%tocheck)
737         # create a dict hostname -> status
738         status = dict ( [ (hostname,'undef') for hostname in tocheck ] )
739         while tocheck:
740             # get their status
741             tocheck_status=self.apiserver.GetNodes(self.auth_root(), tocheck, ['hostname','boot_state' ] )
742             # update status
743             for array in tocheck_status:
744                 hostname=array['hostname']
745                 boot_state=array['boot_state']
746                 if boot_state == target_boot_state:
747                     utils.header ("%s has reached the %s state"%(hostname,target_boot_state))
748                 else:
749                     # if it's a real node, never mind
750                     (site_spec,node_spec)=self.locate_hostname(hostname)
751                     if TestNode.is_real_model(node_spec['node_fields']['model']):
752                         utils.header("WARNING - Real node %s in %s - ignored"%(hostname,boot_state))
753                         # let's cheat
754                         boot_state = target_boot_state
755                     elif datetime.datetime.now() > graceout:
756                         utils.header ("%s still in '%s' state"%(hostname,boot_state))
757                         graceout=datetime.datetime.now()+datetime.timedelta(1)
758                 status[hostname] = boot_state
759             # refresh tocheck
760             tocheck = [ hostname for (hostname,boot_state) in status.iteritems() if boot_state != target_boot_state ]
761             if not tocheck:
762                 return True
763             if datetime.datetime.now() > timeout:
764                 for hostname in tocheck:
765                     utils.header("FAILURE due to %s in '%s' state"%(hostname,status[hostname]))
766                 return False
767             # otherwise, sleep for a while
768             time.sleep(period)
769         # only useful in empty plcs
770         return True
771
772     def nodes_booted(self):
773         return self.nodes_check_boot_state('boot',timeout_minutes=30,silent_minutes=20)
774
775     def check_nodes_ssh(self,debug,timeout_minutes,silent_minutes,period=15):
776         # compute timeout
777         timeout = datetime.datetime.now()+datetime.timedelta(minutes=timeout_minutes)
778         graceout = datetime.datetime.now()+datetime.timedelta(minutes=silent_minutes)
779         vservername=self.vservername
780         if debug: 
781             message="debug"
782             local_key = "keys/%(vservername)s-debug.rsa"%locals()
783         else: 
784             message="boot"
785             local_key = "keys/key1.rsa"
786         node_infos = self.all_node_infos()
787         utils.header("checking ssh access (expected in %s mode) to nodes:"%message)
788         for (nodename,qemuname) in node_infos:
789             utils.header("hostname=%s -- qemubox=%s"%(nodename,qemuname))
790         utils.header("max timeout is %d minutes, silent for %d minutes (period is %s)"%\
791                          (timeout_minutes,silent_minutes,period))
792         while node_infos:
793             for node_info in node_infos:
794                 (hostname,qemuname) = node_info
795                 # try to run 'hostname' in the node
796                 command = TestSsh (hostname,key=local_key).actual_command("hostname;uname -a")
797                 # don't spam logs - show the command only after the grace period 
798                 success = utils.system ( command, silent=datetime.datetime.now() < graceout)
799                 if success==0:
800                     utils.header('Successfully entered root@%s (%s)'%(hostname,message))
801                     # refresh node_infos
802                     node_infos.remove(node_info)
803                 else:
804                     # we will have tried real nodes once, in case they're up - but if not, just skip
805                     (site_spec,node_spec)=self.locate_hostname(hostname)
806                     if TestNode.is_real_model(node_spec['node_fields']['model']):
807                         utils.header ("WARNING : check ssh access into real node %s - skipped"%hostname)
808                         node_infos.remove(node_info)
809             if  not node_infos:
810                 return True
811             if datetime.datetime.now() > timeout:
812                 for (hostname,qemuname) in node_infos:
813                     utils.header("FAILURE to ssh into %s (on %s)"%(hostname,qemuname))
814                 return False
815             # otherwise, sleep for a while
816             time.sleep(period)
817         # only useful in empty plcs
818         return True
819         
820     def nodes_ssh_debug(self):
821         "Tries to ssh into nodes in debug mode with the debug ssh key"
822         return self.check_nodes_ssh(debug=True,timeout_minutes=30,silent_minutes=5)
823     
824     def nodes_ssh_boot(self):
825         "Tries to ssh into nodes in production mode with the root ssh key"
826         return self.check_nodes_ssh(debug=False,timeout_minutes=30,silent_minutes=15)
827     
828     @node_mapper
829     def init_node (self): 
830         "all nodes : init a clean local directory for holding node-dep stuff like iso image..."
831         pass
832     @node_mapper
833     def bootcd (self): 
834         "all nodes: invoke GetBootMedium and store result locally"
835         pass
836     @node_mapper
837     def configure_qemu (self): 
838         "all nodes: compute qemu config qemu.conf and store it locally"
839         pass
840     @node_mapper
841     def reinstall_node (self): 
842         "all nodes: mark PLCAPI boot_state as reinstall"
843         pass
844     @node_mapper
845     def export_qemu (self): 
846         "all nodes: push local node-dep directory on the qemu box"
847         pass
848         
849     ### check hooks : invoke scripts from hooks/{node,slice}
850     def check_hooks_node (self): 
851         return self.locate_first_node().check_hooks()
852     def check_hooks_sliver (self) : 
853         return self.locate_first_sliver().check_hooks()
854     
855     def check_hooks (self):
856         "runs unit tests in the node and slice contexts - see hooks/{node,slice}"
857         return self.check_hooks_node() and self.check_hooks_sliver()
858
859     ### initscripts
860     def do_check_initscripts(self):
861         overall = True
862         for slice_spec in self.plc_spec['slices']:
863             if not slice_spec.has_key('initscriptname'):
864                 continue
865             initscript=slice_spec['initscriptname']
866             for nodename in slice_spec['nodenames']:
867                 (site,node) = self.locate_node (nodename)
868                 # xxx - passing the wrong site - probably harmless
869                 test_site = TestSite (self,site)
870                 test_slice = TestSlice (self,test_site,slice_spec)
871                 test_node = TestNode (self,test_site,node)
872                 test_sliver = TestSliver (self, test_node, test_slice)
873                 if not test_sliver.check_initscript(initscript):
874                     overall = False
875         return overall
876             
877     def check_initscripts(self):
878         "check that the initscripts have triggered"
879         return self.do_check_initscripts()
880     
881     def initscripts (self):
882         "create initscripts with PLCAPI"
883         for initscript in self.plc_spec['initscripts']:
884             utils.pprint('Adding Initscript in plc %s'%self.plc_spec['name'],initscript)
885             self.apiserver.AddInitScript(self.auth_root(),initscript['initscript_fields'])
886         return True
887
888     def clean_initscripts (self):
889         "delete initscripts with PLCAPI"
890         for initscript in self.plc_spec['initscripts']:
891             initscript_name = initscript['initscript_fields']['name']
892             print('Attempting to delete %s in plc %s'%(initscript_name,self.plc_spec['name']))
893             try:
894                 self.apiserver.DeleteInitScript(self.auth_root(),initscript_name)
895                 print initscript_name,'deleted'
896             except:
897                 print 'deletion went wrong - probably did not exist'
898         return True
899
900     ### manage slices
901     def slices (self):
902         "create slices with PLCAPI"
903         return self.do_slices()
904
905     def clean_slices (self):
906         "delete slices with PLCAPI"
907         return self.do_slices("delete")
908
909     def do_slices (self,  action="add"):
910         for slice in self.plc_spec['slices']:
911             site_spec = self.locate_site (slice['sitename'])
912             test_site = TestSite(self,site_spec)
913             test_slice=TestSlice(self,test_site,slice)
914             if action != "add":
915                 utils.header("Deleting slices in site %s"%test_site.name())
916                 test_slice.delete_slice()
917             else:    
918                 utils.pprint("Creating slice",slice)
919                 test_slice.create_slice()
920                 utils.header('Created Slice %s'%slice['slice_fields']['name'])
921         return True
922         
923     @slice_mapper_options
924     def check_slice(self): 
925         "tries to ssh-enter the slice with the user key, to ensure slice creation"
926         pass
927
928     @node_mapper
929     def clear_known_hosts (self): 
930         "remove test nodes entries from the local known_hosts file"
931         pass
932     
933     @node_mapper
934     def start_node (self) : 
935         "all nodes: start the qemu instance (also runs qemu-bridge-init start)"
936         pass
937
938     def check_tcp (self):
939         "check TCP connectivity between 2 slices (or in loopback if only one is defined)"
940         specs = self.plc_spec['tcp_test']
941         overall=True
942         for spec in specs:
943             port = spec['port']
944             # server side
945             s_test_sliver = self.locate_sliver_obj (spec['server_node'],spec['server_slice'])
946             if not s_test_sliver.run_tcp_server(port,timeout=10):
947                 overall=False
948                 break
949
950             # idem for the client side
951             c_test_sliver = self.locate_sliver_obj(spec['server_node'],spec['server_slice'])
952             if not c_test_sliver.run_tcp_client(s_test_sliver.test_node.name(),port):
953                 overall=False
954         return overall
955
956     def plcsh_stress_test (self):
957         "runs PLCAPI stress test, that checks Add/Update/Delete on all types - preserves contents"
958         # install the stress-test in the plc image
959         location = "/usr/share/plc_api/plcsh_stress_test.py"
960         remote="/vservers/%s/%s"%(self.vservername,location)
961         self.test_ssh.copy_abs("plcsh_stress_test.py",remote)
962         command = location
963         command += " -- --check"
964         if self.options.size == 1:
965             command +=  " --tiny"
966         return ( self.run_in_guest(command) == 0)
967
968     # populate runs the same utility without slightly different options
969     # in particular runs with --preserve (dont cleanup) and without --check
970     # also it gets run twice, once with the --foreign option for creating fake foreign entries
971
972     ### install_sfa_rpm
973     def install_sfa(self):
974         "yum install sfa, sfa-plc and sfa-client"
975         if self.options.personality == "linux32":
976             arch = "i386"
977         elif self.options.personality == "linux64":
978             arch = "x86_64"
979         else:
980             raise Exception, "Unsupported personality %r"%self.options.personality
981         return self.run_in_guest("yum -y install sfa sfa-client sfa-plc sfa-sfatables")==0
982
983     ###
984     def configure_sfa(self):
985         "run sfa-config-tty"
986         tmpname='%s.sfa-config-tty'%(self.name())
987         fileconf=open(tmpname,'w')
988         for var in [ 'SFA_REGISTRY_ROOT_AUTH',
989                      'SFA_REGISTRY_LEVEL1_AUTH',
990                      'SFA_REGISTRY_HOST',
991                      'SFA_AGGREGATE_HOST',
992                      'SFA_SM_HOST',
993                      'SFA_PLC_USER',
994                      'SFA_PLC_PASSWORD',
995                      'SFA_PLC_DB_HOST',
996                      'SFA_PLC_DB_USER',
997                      'SFA_PLC_DB_PASSWORD',
998                      'SFA_PLC_URL']:
999             fileconf.write ('e %s\n%s\n'%(var,self.plc_spec['sfa'][var]))
1000         fileconf.write('w\n')
1001         fileconf.write('R\n')
1002         fileconf.write('q\n')
1003         fileconf.close()
1004         utils.system('cat %s'%tmpname)
1005         self.run_in_guest_piped('cat %s'%tmpname,'sfa-config-tty')
1006         utils.system('rm %s'%tmpname)
1007         return True
1008
1009     def import_sfa(self):
1010         "sfa-import-plc"
1011         auth=self.plc_spec['sfa']['SFA_REGISTRY_ROOT_AUTH']
1012         return self.run_in_guest('sfa-import-plc.py')==0
1013 # not needed anymore
1014 #        self.run_in_guest('cp /etc/sfa/authorities/%s/%s.pkey /etc/sfa/authorities/server.key'%(auth,auth))
1015
1016     def start_sfa(self):
1017         "service sfa start"
1018         return self.run_in_guest('service sfa start')==0
1019
1020     def setup_sfa(self):
1021         "sfi client configuration"
1022         dir_name=".sfi"
1023         if os.path.exists(dir_name):
1024            utils.system('rm -rf %s'%dir_name)
1025         utils.system('mkdir %s'%dir_name)
1026         file_name=dir_name + os.sep + 'fake-pi1.pkey'
1027         fileconf=open(file_name,'w')
1028         fileconf.write (self.plc_spec['keys'][0]['private'])
1029         fileconf.close()
1030
1031         file_name=dir_name + os.sep + 'sfi_config'
1032         fileconf=open(file_name,'w')
1033         SFI_AUTH=self.plc_spec['sfa']['SFA_REGISTRY_ROOT_AUTH']+".main"
1034         fileconf.write ("SFI_AUTH='%s'"%SFI_AUTH)
1035         fileconf.write('\n')
1036         SFI_USER=SFI_AUTH+'.fake-pi1'
1037         fileconf.write ("SFI_USER='%s'"%SFI_USER)
1038         fileconf.write('\n')
1039         SFI_REGISTRY='http://' + self.plc_spec['sfa']['SFA_PLC_DB_HOST'] + ':12345/'
1040         fileconf.write ("SFI_REGISTRY='%s'"%SFI_REGISTRY)
1041         fileconf.write('\n')
1042         SFI_SM='http://' + self.plc_spec['sfa']['SFA_PLC_DB_HOST'] + ':12347/'
1043         fileconf.write ("SFI_SM='%s'"%SFI_SM)
1044         fileconf.write('\n')
1045         fileconf.close()
1046
1047         file_name=dir_name + os.sep + 'person.xml'
1048         fileconf=open(file_name,'w')
1049         for record in self.plc_spec['sfa']['sfa_person_xml']:
1050            person_record=record
1051         fileconf.write(person_record)
1052         fileconf.write('\n')
1053         fileconf.close()
1054
1055         file_name=dir_name + os.sep + 'slice.xml'
1056         fileconf=open(file_name,'w')
1057         for record in self.plc_spec['sfa']['sfa_slice_xml']:
1058             slice_record=record
1059         #slice_record=self.plc_spec['sfa']['sfa_slice_xml']
1060         fileconf.write(slice_record)
1061         fileconf.write('\n')
1062         fileconf.close()
1063
1064         file_name=dir_name + os.sep + 'slice.rspec'
1065         fileconf=open(file_name,'w')
1066         slice_rspec=''
1067         for (key, value) in self.plc_spec['sfa']['sfa_slice_rspec'].items():
1068             slice_rspec +=value 
1069         fileconf.write(slice_rspec)
1070         fileconf.write('\n')
1071         fileconf.close()
1072         location = "root/"
1073         remote="/vservers/%s/%s"%(self.vservername,location)
1074         self.test_ssh.copy_abs(dir_name, remote, recursive=True)
1075
1076         #utils.system('cat %s'%tmpname)
1077         utils.system('rm -rf %s'%dir_name)
1078         return True
1079
1080     def add_sfa(self):
1081         "run sfi.py add (on Registry) and sfi.py create (on SM) to form new objects"
1082         test_plc=self
1083         test_user_sfa=TestUserSfa(test_plc,self.plc_spec['sfa'])
1084         success=test_user_sfa.add_user()
1085
1086         for slice_spec in self.plc_spec['sfa']['slices_sfa']:
1087             site_spec = self.locate_site (slice_spec['sitename'])
1088             test_site = TestSite(self,site_spec)
1089             test_slice_sfa=TestSliceSfa(test_plc,test_site,slice_spec)
1090             success1=test_slice_sfa.add_slice()
1091             success2=test_slice_sfa.create_slice()
1092         return success and success1 and success2
1093
1094     def update_sfa(self):
1095         "run sfi.py update (on Registry) and sfi.py create (on SM) on existing objects"
1096         test_plc=self
1097         test_user_sfa=TestUserSfa(test_plc,self.plc_spec['sfa'])
1098         success1=test_user_sfa.update_user()
1099         
1100         for slice_spec in self.plc_spec['sfa']['slices_sfa']:
1101             site_spec = self.locate_site (slice_spec['sitename'])
1102             test_site = TestSite(self,site_spec)
1103             test_slice_sfa=TestSliceSfa(test_plc,test_site,slice_spec)
1104             success2=test_slice_sfa.update_slice()
1105         return success1 and success2
1106
1107     def view_sfa(self):
1108         "run sfi.py list and sfi.py show (both on Registry) and sfi.py slices and sfi.py resources (both on SM)"
1109         auth=self.plc_spec['sfa']['SFA_REGISTRY_ROOT_AUTH']
1110         return \
1111         self.run_in_guest("sfi.py -d /root/.sfi/ list %s.main"%auth)==0 and \
1112         self.run_in_guest("sfi.py -d /root/.sfi/ show %s.main"%auth)==0 and \
1113         self.run_in_guest("sfi.py -d /root/.sfi/ slices")==0 and \
1114         self.run_in_guest("sfi.py -d /root/.sfi/ resources -o resources")==0
1115
1116     @slice_mapper_options_sfa
1117     def check_slice_sfa(self): 
1118         "tries to ssh-enter the SFA slice"
1119         pass
1120
1121     def delete_sfa(self):
1122         "run sfi.py delete (on SM), sfi.py remove (on Registry)"
1123         test_plc=self
1124         test_user_sfa=TestUserSfa(test_plc,self.plc_spec['sfa'])
1125         success1=test_user_sfa.delete_user()
1126         for slice_spec in self.plc_spec['sfa']['slices_sfa']:
1127             site_spec = self.locate_site (slice_spec['sitename'])
1128             test_site = TestSite(self,site_spec)
1129             test_slice_sfa=TestSliceSfa(test_plc,test_site,slice_spec)
1130             success2=test_slice_sfa.delete_slice()
1131
1132         return success1 and success2
1133
1134     def stop_sfa(self):
1135         "service sfa stop"
1136         return self.run_in_guest('service sfa stop')==0
1137
1138     def populate (self):
1139         "creates random entries in the PLCAPI"
1140         # install the stress-test in the plc image
1141         location = "/usr/share/plc_api/plcsh_stress_test.py"
1142         remote="/vservers/%s/%s"%(self.vservername,location)
1143         self.test_ssh.copy_abs("plcsh_stress_test.py",remote)
1144         command = location
1145         command += " -- --preserve --short-names"
1146         local = (self.run_in_guest(command) == 0);
1147         # second run with --foreign
1148         command += ' --foreign'
1149         remote = (self.run_in_guest(command) == 0);
1150         return ( local and remote)
1151
1152     def gather_logs (self):
1153         "gets all possible logs from plc's/qemu node's/slice's for future reference"
1154         # (1.a) get the plc's /var/log/ and store it locally in logs/myplc.var-log.<plcname>/*
1155         # (1.b) get the plc's  /var/lib/pgsql/data/pg_log/ -> logs/myplc.pgsql-log.<plcname>/*
1156         # (2) get all the nodes qemu log and store it as logs/node.qemu.<node>.log
1157         # (3) get the nodes /var/log and store is as logs/node.var-log.<node>/*
1158         # (4) as far as possible get the slice's /var/log as logs/sliver.var-log.<sliver>/*
1159         # (1.a)
1160         print "-------------------- TestPlc.gather_logs : PLC's /var/log"
1161         self.gather_var_logs ()
1162         # (1.b)
1163         print "-------------------- TestPlc.gather_logs : PLC's /var/lib/psql/data/pg_log/"
1164         self.gather_pgsql_logs ()
1165         # (2) 
1166         print "-------------------- TestPlc.gather_logs : nodes's QEMU logs"
1167         for site_spec in self.plc_spec['sites']:
1168             test_site = TestSite (self,site_spec)
1169             for node_spec in site_spec['nodes']:
1170                 test_node=TestNode(self,test_site,node_spec)
1171                 test_node.gather_qemu_logs()
1172         # (3)
1173         print "-------------------- TestPlc.gather_logs : nodes's /var/log"
1174         self.gather_nodes_var_logs()
1175         # (4)
1176         print "-------------------- TestPlc.gather_logs : sample sliver's /var/log"
1177         self.gather_slivers_var_logs()
1178         return True
1179
1180     def gather_slivers_var_logs(self):
1181         for test_sliver in self.all_sliver_objs():
1182             remote = test_sliver.tar_var_logs()
1183             utils.system("mkdir -p logs/sliver.var-log.%s"%test_sliver.name())
1184             command = remote + " | tar -C logs/sliver.var-log.%s -xf -"%test_sliver.name()
1185             utils.system(command)
1186         return True
1187
1188     def gather_var_logs (self):
1189         utils.system("mkdir -p logs/myplc.var-log.%s"%self.name())
1190         to_plc = self.actual_command_in_guest("tar -C /var/log/ -cf - .")        
1191         command = to_plc + "| tar -C logs/myplc.var-log.%s -xf -"%self.name()
1192         utils.system(command)
1193         command = "chmod a+r,a+x logs/myplc.var-log.%s/httpd"%self.name()
1194         utils.system(command)
1195
1196     def gather_pgsql_logs (self):
1197         utils.system("mkdir -p logs/myplc.pgsql-log.%s"%self.name())
1198         to_plc = self.actual_command_in_guest("tar -C /var/lib/pgsql/data/pg_log/ -cf - .")        
1199         command = to_plc + "| tar -C logs/myplc.pgsql-log.%s -xf -"%self.name()
1200         utils.system(command)
1201
1202     def gather_nodes_var_logs (self):
1203         for site_spec in self.plc_spec['sites']:
1204             test_site = TestSite (self,site_spec)
1205             for node_spec in site_spec['nodes']:
1206                 test_node=TestNode(self,test_site,node_spec)
1207                 test_ssh = TestSsh (test_node.name(),key="keys/key1.rsa")
1208                 command = test_ssh.actual_command("tar -C /var/log -cf - .")
1209                 command = command + "| tar -C logs/node.var-log.%s -xf -"%test_node.name()
1210                 utils.system("mkdir -p logs/node.var-log.%s"%test_node.name())
1211                 utils.system(command)
1212
1213
1214     # returns the filename to use for sql dump/restore, using options.dbname if set
1215     def dbfile (self, database):
1216         # uses options.dbname if it is found
1217         try:
1218             name=self.options.dbname
1219             if not isinstance(name,StringTypes):
1220                 raise Exception
1221         except:
1222             t=datetime.datetime.now()
1223             d=t.date()
1224             name=str(d)
1225         return "/root/%s-%s.sql"%(database,name)
1226
1227     def db_dump(self):
1228         'dump the planetlab5 DB in /root in the PLC - filename has time'
1229         dump=self.dbfile("planetab5")
1230         self.run_in_guest('pg_dump -U pgsqluser planetlab5 -f '+ dump)
1231         utils.header('Dumped planetlab5 database in %s'%dump)
1232         return True
1233
1234     def db_restore(self):
1235         'restore the planetlab5 DB - looks broken, but run -n might help'
1236         dump=self.dbfile("planetab5")
1237         ##stop httpd service
1238         self.run_in_guest('service httpd stop')
1239         # xxx - need another wrapper
1240         self.run_in_guest_piped('echo drop database planetlab5','psql --user=pgsqluser template1')
1241         self.run_in_guest('createdb -U postgres --encoding=UNICODE --owner=pgsqluser planetlab5')
1242         self.run_in_guest('psql -U pgsqluser planetlab5 -f '+dump)
1243         ##starting httpd service
1244         self.run_in_guest('service httpd start')
1245
1246         utils.header('Database restored from ' + dump)
1247
1248     @standby_generic 
1249     def standby_1(): pass
1250     @standby_generic 
1251     def standby_2(): pass
1252     @standby_generic 
1253     def standby_3(): pass
1254     @standby_generic 
1255     def standby_4(): pass
1256     @standby_generic 
1257     def standby_5(): pass
1258     @standby_generic 
1259     def standby_6(): pass
1260     @standby_generic 
1261     def standby_7(): pass
1262     @standby_generic 
1263     def standby_8(): pass
1264     @standby_generic 
1265     def standby_9(): pass
1266     @standby_generic 
1267     def standby_10(): pass
1268     @standby_generic 
1269     def standby_11(): pass
1270     @standby_generic 
1271     def standby_12(): pass
1272     @standby_generic 
1273     def standby_13(): pass
1274     @standby_generic 
1275     def standby_14(): pass
1276     @standby_generic 
1277     def standby_15(): pass
1278     @standby_generic 
1279     def standby_16(): pass
1280     @standby_generic 
1281     def standby_17(): pass
1282     @standby_generic 
1283     def standby_18(): pass
1284     @standby_generic 
1285     def standby_19(): pass
1286     @standby_generic 
1287     def standby_20(): pass