7 from types import StringTypes
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
21 # step methods must take (self) and return a boolean (options is a member of the class)
23 def standby(minutes,dry_run):
24 utils.header('Entering StandBy for %d mn'%minutes)
28 time.sleep(60*minutes)
31 def standby_generic (func):
33 minutes=int(func.__name__.split("_")[1])
34 return standby(minutes,self.options.dry_run)
37 def node_mapper (method):
40 node_method = TestNode.__dict__[method.__name__]
41 for site_spec in self.plc_spec['sites']:
42 test_site = TestSite (self,site_spec)
43 for node_spec in site_spec['nodes']:
44 test_node = TestNode (self,test_site,node_spec)
45 if not node_method(test_node): overall=False
49 def slice_mapper_options (method):
52 slice_method = TestSlice.__dict__[method.__name__]
53 for slice_spec in self.plc_spec['slices']:
54 site_spec = self.locate_site (slice_spec['sitename'])
55 test_site = TestSite(self,site_spec)
56 test_slice=TestSlice(self,test_site,slice_spec)
57 if not slice_method(test_slice,self.options): overall=False
66 'display','uninstall','install','install_rpm',
67 'configure', 'start', 'fetch_keys', SEP,
68 'store_keys', 'clear_known_hosts', 'initscripts', SEP,
69 'sites', 'nodes', 'slices', 'nodegroups', SEP,
70 'init_node','bootcd', 'configure_qemu', 'export_qemu',
71 'kill_all_qemus', 'reinstall_node','start_node', SEP,
72 # better use of time: do this now that the nodes are taking off
73 'plcsh_stress_test', SEP,
74 'nodes_ssh_debug', 'nodes_ssh_boot', 'check_slice', 'check_initscripts', SEP,
76 'force_gather_logs', 'force_kill_qemus', 'force_record_tracker','force_free_tracker',
79 'stop_all_vservers','fresh_install', 'cache_rpm', 'stop', 'vs_start', SEP,
81 'clean_initscripts', 'clean_nodegroups','clean_all_sites', SEP,
82 'clean_sites', 'clean_nodes',
83 'clean_slices', 'clean_keys', SEP,
84 'show_boxes', 'list_all_qemus', 'list_qemus', SEP,
85 'db_dump' , 'db_restore', 'cleanup_trackers', 'cleanup_all_trackers',
86 'standby_1 through 20',
90 def printable_steps (list):
91 return " ".join(list).replace(" "+SEP+" "," \\\n")
93 def valid_step (step):
96 def __init__ (self,plc_spec,options):
97 self.plc_spec=plc_spec
99 self.test_ssh=TestSsh(self.plc_spec['hostname'],self.options.buildname)
101 self.vserverip=plc_spec['vserverip']
102 self.vservername=plc_spec['vservername']
103 self.url="https://%s:443/PLCAPI/"%plc_spec['vserverip']
106 raise Exception,'chroot-based myplc testing is deprecated'
107 self.apiserver=TestApiserver(self.url,options.dry_run)
110 name=self.plc_spec['name']
111 return "%s.%s"%(name,self.vservername)
114 return self.plc_spec['hostname']
117 return self.test_ssh.is_local()
119 # define the API methods on this object through xmlrpc
120 # would help, but not strictly necessary
124 def actual_command_in_guest (self,command):
125 return self.test_ssh.actual_command(self.host_to_guest(command))
127 def start_guest (self):
128 return utils.system(self.test_ssh.actual_command(self.start_guest_in_host()))
130 def run_in_guest (self,command):
131 return utils.system(self.actual_command_in_guest(command))
133 def run_in_host (self,command):
134 return self.test_ssh.run_in_buildname(command)
136 #command gets run in the vserver
137 def host_to_guest(self,command):
138 return "vserver %s exec %s"%(self.vservername,command)
140 #command gets run in the vserver
141 def start_guest_in_host(self):
142 return "vserver %s start"%(self.vservername)
145 def run_in_guest_piped (self,local,remote):
146 return utils.system(local+" | "+self.test_ssh.actual_command(self.host_to_guest(remote),keep_stdin=True))
148 def auth_root (self):
149 return {'Username':self.plc_spec['PLC_ROOT_USER'],
150 'AuthMethod':'password',
151 'AuthString':self.plc_spec['PLC_ROOT_PASSWORD'],
152 'Role' : self.plc_spec['role']
154 def locate_site (self,sitename):
155 for site in self.plc_spec['sites']:
156 if site['site_fields']['name'] == sitename:
158 if site['site_fields']['login_base'] == sitename:
160 raise Exception,"Cannot locate site %s"%sitename
162 def locate_node (self,nodename):
163 for site in self.plc_spec['sites']:
164 for node in site['nodes']:
165 if node['name'] == nodename:
167 raise Exception,"Cannot locate node %s"%nodename
169 def locate_hostname (self,hostname):
170 for site in self.plc_spec['sites']:
171 for node in site['nodes']:
172 if node['node_fields']['hostname'] == hostname:
174 raise Exception,"Cannot locate hostname %s"%hostname
176 def locate_key (self,keyname):
177 for key in self.plc_spec['keys']:
178 if key['name'] == keyname:
180 raise Exception,"Cannot locate key %s"%keyname
182 def locate_slice (self, slicename):
183 for slice in self.plc_spec['slices']:
184 if slice['slice_fields']['name'] == slicename:
186 raise Exception,"Cannot locate slice %s"%slicename
188 def all_sliver_objs (self):
190 for slice_spec in self.plc_spec['slices']:
191 slicename = slice_spec['slice_fields']['name']
192 for nodename in slice_spec['nodenames']:
193 result.append(self.locate_sliver_obj (nodename,slicename))
196 def locate_sliver_obj (self,nodename,slicename):
197 (site,node) = self.locate_node(nodename)
198 slice = self.locate_slice (slicename)
200 test_site = TestSite (self, site)
201 test_node = TestNode (self, test_site,node)
202 # xxx the slice site is assumed to be the node site - mhh - probably harmless
203 test_slice = TestSlice (self, test_site, slice)
204 return TestSliver (self, test_node, test_slice)
206 def locate_first_node(self):
207 nodename=self.plc_spec['slices'][0]['nodenames'][0]
208 (site,node) = self.locate_node(nodename)
209 test_site = TestSite (self, site)
210 test_node = TestNode (self, test_site,node)
213 def locate_first_sliver (self):
214 slice_spec=self.plc_spec['slices'][0]
215 slicename=slice_spec['slice_fields']['name']
216 nodename=slice_spec['nodenames'][0]
217 return self.locate_sliver_obj(nodename,slicename)
219 # all different hostboxes used in this plc
220 def gather_hostBoxes(self):
221 # maps on sites and nodes, return [ (host_box,test_node) ]
223 for site_spec in self.plc_spec['sites']:
224 test_site = TestSite (self,site_spec)
225 for node_spec in site_spec['nodes']:
226 test_node = TestNode (self, test_site, node_spec)
227 if not test_node.is_real():
228 tuples.append( (test_node.host_box(),test_node) )
229 # transform into a dict { 'host_box' -> [ test_node .. ] }
231 for (box,node) in tuples:
232 if not result.has_key(box):
235 result[box].append(node)
238 # a step for checking this stuff
239 def show_boxes (self):
240 for (box,nodes) in self.gather_hostBoxes().iteritems():
241 print box,":"," + ".join( [ node.name() for node in nodes ] )
244 # make this a valid step
245 def kill_all_qemus(self):
246 # this is the brute force version, kill all qemus on that host box
247 for (box,nodes) in self.gather_hostBoxes().iteritems():
248 # pass the first nodename, as we don't push template-qemu on testboxes
249 nodedir=nodes[0].nodedir()
250 TestBox(box,self.options.buildname).kill_all_qemus(nodedir)
253 # make this a valid step
254 def list_all_qemus(self):
255 for (box,nodes) in self.gather_hostBoxes().iteritems():
256 # this is the brute force version, kill all qemus on that host box
257 TestBox(box,self.options.buildname).list_all_qemus()
260 # kill only the right qemus
261 def list_qemus(self):
262 for (box,nodes) in self.gather_hostBoxes().iteritems():
263 # the fine-grain version
268 # kill only the right qemus
269 def kill_qemus(self):
270 for (box,nodes) in self.gather_hostBoxes().iteritems():
271 # the fine-grain version
276 #################### display config
278 self.display_pass (1)
279 self.display_pass (2)
283 def display_pass (self,passno):
284 for (key,val) in self.plc_spec.iteritems():
288 self.display_site_spec(site)
289 for node in site['nodes']:
290 self.display_node_spec(node)
291 elif key=='initscripts':
292 for initscript in val:
293 self.display_initscript_spec (initscript)
296 self.display_slice_spec (slice)
299 self.display_key_spec (key)
301 if key not in ['sites','initscripts','slices','keys']:
302 print '* ',key,':',val
304 def display_site_spec (self,site):
305 print '* ======== site',site['site_fields']['name']
306 for (k,v) in site.iteritems():
309 print '* ','nodes : ',
311 print node['node_fields']['hostname'],'',
317 print user['name'],'',
319 elif k == 'site_fields':
320 print '* login_base',':',v['login_base']
321 elif k == 'address_fields':
325 PrettyPrinter(indent=8,depth=2).pprint(v)
327 def display_initscript_spec (self,initscript):
328 print '* ======== initscript',initscript['initscript_fields']['name']
330 def display_key_spec (self,key):
331 print '* ======== key',key['name']
333 def display_slice_spec (self,slice):
334 print '* ======== slice',slice['slice_fields']['name']
335 for (k,v) in slice.iteritems():
348 elif k=='slice_fields':
349 print '* fields',':',
350 print 'max_nodes=',v['max_nodes'],
355 def display_node_spec (self,node):
356 print "* node",node['name'],"host_box=",node['host_box'],
357 print "hostname=",node['node_fields']['hostname'],
358 print "ip=",node['interface_fields']['ip']
361 # another entry point for just showing the boxes involved
362 def display_mapping (self):
363 TestPlc.display_mapping_plc(self.plc_spec)
367 def display_mapping_plc (plc_spec):
368 print '* MyPLC',plc_spec['name']
369 print '*\tvserver address = root@%s:/vservers/%s'%(plc_spec['hostname'],plc_spec['vservername'])
370 print '*\tIP = %s/%s'%(plc_spec['PLC_API_HOST'],plc_spec['vserverip'])
371 for site_spec in plc_spec['sites']:
372 for node_spec in site_spec['nodes']:
373 TestPlc.display_mapping_node(node_spec)
376 def display_mapping_node (node_spec):
377 print '* NODE %s'%(node_spec['name'])
378 print '*\tqemu box %s'%node_spec['host_box']
379 print '*\thostname=%s'%node_spec['node_fields']['hostname']
381 ### utility methods for handling the pool of IP addresses allocated to plcs
383 # (*) running plcs are recorded in the file named ~/running-test-plcs
384 # (*) this file contains a line for each running plc, older first
385 # (*) each line contains the vserver name + the hostname of the (vserver) testbox where it sits
386 # (*) the free_tracker method performs a vserver stop on the oldest entry
387 # (*) the record_tracker method adds an entry at the bottom of the file
388 # (*) the cleanup_tracker method stops all known vservers and removes the tracker file
390 TRACKER_FILE=os.environ['HOME']+"/running-test-plcs"
391 # how many concurrent plcs are we keeping alive - adjust with the IP pool size
392 TRACKER_KEEP_VSERVERS = 12
394 def record_tracker (self):
396 lines=file(TestPlc.TRACKER_FILE).readlines()
400 this_line="%s %s\n"%(self.vservername,self.test_ssh.hostname)
403 print 'this vserver is already included in %s'%TestPlc.TRACKER_FILE
405 if self.options.dry_run:
406 print 'dry_run: record_tracker - skipping tracker update'
408 tracker=file(TestPlc.TRACKER_FILE,"w")
409 for line in lines+[this_line]:
412 print "Recorded %s in running plcs on host %s"%(self.vservername,self.test_ssh.hostname)
415 def free_tracker (self, keep_vservers=None):
416 if not keep_vservers: keep_vservers=TestPlc.TRACKER_KEEP_VSERVERS
418 lines=file(TestPlc.TRACKER_FILE).readlines()
420 print 'dry_run: free_tracker - skipping tracker update'
422 how_many = len(lines) - keep_vservers
423 # nothing todo until we have more than keep_vservers in the tracker
425 print 'free_tracker : limit %d not reached'%keep_vservers
427 to_stop = lines[:how_many]
428 to_keep = lines[how_many:]
431 [vname,hostname]=line.split()
432 command=TestSsh(hostname).actual_command("vserver --silent %s stop"%vname)
433 utils.system(command)
434 if self.options.dry_run:
435 print 'dry_run: free_tracker would stop %d vservers'%len(to_stop)
436 for line in to_stop: print line,
437 print 'dry_run: free_tracker would keep %d vservers'%len(to_keep)
438 for line in to_keep: print line,
440 print "Storing %d remaining vservers in %s"%(len(to_keep),TestPlc.TRACKER_FILE)
441 tracker=open(TestPlc.TRACKER_FILE,"w")
447 # this should/could stop only the ones in TRACKER_FILE if that turns out to be reliable
448 def cleanup_trackers (self):
450 for line in TestPlc.TRACKER_FILE.readlines():
451 [vname,hostname]=line.split()
452 stop="vserver --silent %s stop"%vname
453 command=TestSsh(hostname).actual_command(stop)
454 utils.system(command)
455 clean_tracker = "rm -f %s"%TestPlc.TRACKER_FILE
456 utils.system(self.test_ssh.actual_command(clean_tracker))
460 # this should/could stop only the ones in TRACKER_FILE if that turns out to be reliable
461 def cleanup_all_trackers (self):
462 stop_all = "cd /vservers ; for i in * ; do vserver --silent $i stop ; done"
463 utils.system(self.test_ssh.actual_command(stop_all))
464 clean_tracker = "rm -f %s"%TestPlc.TRACKER_FILE
465 utils.system(self.test_ssh.actual_command(clean_tracker))
469 self.run_in_host("vserver --silent %s delete"%self.vservername)
475 # a full path for the local calls
476 build_dir=os.path.dirname(sys.argv[0])
477 # sometimes this is empty - set to "." in such a case
478 if not build_dir: build_dir="."
479 build_dir += "/build"
481 # use a standard name - will be relative to remote buildname
483 # run checkout in any case - would do an update if already exists
484 build_checkout = "svn checkout %s %s"%(self.options.build_url,build_dir)
485 if self.run_in_host(build_checkout) != 0:
487 # the repo url is taken from arch-rpms-url
488 # with the last step (i386) removed
489 repo_url = self.options.arch_rpms_url
490 for level in [ 'arch' ]:
491 repo_url = os.path.dirname(repo_url)
492 # pass the vbuild-nightly options to vtest-init-vserver
494 test_env_options += " -p %s"%self.options.personality
495 test_env_options += " -d %s"%self.options.pldistro
496 test_env_options += " -f %s"%self.options.fcdistro
497 script="vtest-init-vserver.sh"
498 vserver_name = self.vservername
499 vserver_options="--netdev eth0 --interface %s"%self.vserverip
501 vserver_hostname=socket.gethostbyaddr(self.vserverip)[0]
502 vserver_options += " --hostname %s"%vserver_hostname
505 create_vserver="%(build_dir)s/%(script)s %(test_env_options)s %(vserver_name)s %(repo_url)s -- %(vserver_options)s"%locals()
506 return self.run_in_host(create_vserver) == 0
509 def install_rpm(self):
510 if self.options.personality == "linux32":
512 elif self.options.personality == "linux64":
515 raise Exception, "Unsupported personality %r"%self.options.personality
517 self.run_in_guest("yum -y install myplc-native")==0 and \
518 self.run_in_guest("yum -y install noderepo-%s-%s"%(self.options.pldistro,arch))==0
522 tmpname='%s.plc-config-tty'%(self.name())
523 fileconf=open(tmpname,'w')
524 for var in [ 'PLC_NAME',
528 'PLC_MAIL_SUPPORT_ADDRESS',
535 fileconf.write ('e %s\n%s\n'%(var,self.plc_spec[var]))
536 fileconf.write('w\n')
537 fileconf.write('q\n')
539 utils.system('cat %s'%tmpname)
540 self.run_in_guest_piped('cat %s'%tmpname,'plc-config-tty')
541 utils.system('rm %s'%tmpname)
545 self.run_in_guest('service plc start')
549 self.run_in_guest('service plc stop')
556 # stores the keys from the config for further use
557 def store_keys(self):
558 for key_spec in self.plc_spec['keys']:
559 TestKey(self,key_spec).store_key()
562 def clean_keys(self):
563 utils.system("rm -rf %s/keys/"%os.path(sys.argv[0]))
565 # fetches the ssh keys in the plc's /etc/planetlab and stores them in keys/
566 # for later direct access to the nodes
567 def fetch_keys(self):
569 if not os.path.isdir(dir):
571 vservername=self.vservername
573 prefix = 'root_ssh_key'
574 for ext in [ 'pub', 'rsa' ] :
575 src="/vservers/%(vservername)s/etc/planetlab/%(prefix)s.%(ext)s"%locals()
576 dst="keys/%(vservername)s.%(ext)s"%locals()
577 if self.test_ssh.fetch(src,dst) != 0: overall=False
578 prefix = 'debug_ssh_key'
579 for ext in [ 'pub', 'rsa' ] :
580 src="/vservers/%(vservername)s/etc/planetlab/%(prefix)s.%(ext)s"%locals()
581 dst="keys/%(vservername)s-debug.%(ext)s"%locals()
582 if self.test_ssh.fetch(src,dst) != 0: overall=False
586 return self.do_sites()
588 def clean_sites (self):
589 return self.do_sites(action="delete")
591 def do_sites (self,action="add"):
592 for site_spec in self.plc_spec['sites']:
593 test_site = TestSite (self,site_spec)
594 if (action != "add"):
595 utils.header("Deleting site %s in %s"%(test_site.name(),self.name()))
596 test_site.delete_site()
597 # deleted with the site
598 #test_site.delete_users()
601 utils.header("Creating site %s & users in %s"%(test_site.name(),self.name()))
602 test_site.create_site()
603 test_site.create_users()
606 def clean_all_sites (self):
607 print 'auth_root',self.auth_root()
608 site_ids = [s['site_id'] for s in self.apiserver.GetSites(self.auth_root(), {}, ['site_id'])]
609 for site_id in site_ids:
610 print 'Deleting site_id',site_id
611 self.apiserver.DeleteSite(self.auth_root(),site_id)
614 return self.do_nodes()
615 def clean_nodes (self):
616 return self.do_nodes(action="delete")
618 def do_nodes (self,action="add"):
619 for site_spec in self.plc_spec['sites']:
620 test_site = TestSite (self,site_spec)
622 utils.header("Deleting nodes in site %s"%test_site.name())
623 for node_spec in site_spec['nodes']:
624 test_node=TestNode(self,test_site,node_spec)
625 utils.header("Deleting %s"%test_node.name())
626 test_node.delete_node()
628 utils.header("Creating nodes for site %s in %s"%(test_site.name(),self.name()))
629 for node_spec in site_spec['nodes']:
630 utils.pprint('Creating node %s'%node_spec,node_spec)
631 test_node = TestNode (self,test_site,node_spec)
632 test_node.create_node ()
635 def nodegroups (self):
636 return self.do_nodegroups("add")
637 def clean_nodegroups (self):
638 return self.do_nodegroups("delete")
640 # create nodegroups if needed, and populate
641 def do_nodegroups (self, action="add"):
642 # 1st pass to scan contents
644 for site_spec in self.plc_spec['sites']:
645 test_site = TestSite (self,site_spec)
646 for node_spec in site_spec['nodes']:
647 test_node=TestNode (self,test_site,node_spec)
648 if node_spec.has_key('nodegroups'):
649 nodegroupnames=node_spec['nodegroups']
650 if isinstance(nodegroupnames,StringTypes):
651 nodegroupnames = [ nodegroupnames ]
652 for nodegroupname in nodegroupnames:
653 if not groups_dict.has_key(nodegroupname):
654 groups_dict[nodegroupname]=[]
655 groups_dict[nodegroupname].append(test_node.name())
656 auth=self.auth_root()
658 for (nodegroupname,group_nodes) in groups_dict.iteritems():
660 print 'nodegroups:','dealing with nodegroup',nodegroupname,'on nodes',group_nodes
661 # first, check if the nodetagtype is here
662 tag_types = self.apiserver.GetTagTypes(auth,{'tagname':nodegroupname})
664 tag_type_id = tag_types[0]['tag_type_id']
666 tag_type_id = self.apiserver.AddTagType(auth,
667 {'tagname':nodegroupname,
668 'description': 'for nodegroup %s'%nodegroupname,
671 print 'located tag (type)',nodegroupname,'as',tag_type_id
673 nodegroups = self.apiserver.GetNodeGroups (auth, {'groupname':nodegroupname})
675 self.apiserver.AddNodeGroup(auth, nodegroupname, tag_type_id, 'yes')
676 print 'created nodegroup',nodegroupname,'from tagname',nodegroupname,'and value','yes'
677 # set node tag on all nodes, value='yes'
678 for nodename in group_nodes:
680 self.apiserver.AddNodeTag(auth, nodename, nodegroupname, "yes")
682 traceback.print_exc()
683 print 'node',nodename,'seems to already have tag',nodegroupname
686 expect_yes = self.apiserver.GetNodeTags(auth,
687 {'hostname':nodename,
688 'tagname':nodegroupname},
689 ['tagvalue'])[0]['tagvalue']
690 if expect_yes != "yes":
691 print 'Mismatch node tag on node',nodename,'got',expect_yes
694 if not self.options.dry_run:
695 print 'Cannot find tag',nodegroupname,'on node',nodename
699 print 'cleaning nodegroup',nodegroupname
700 self.apiserver.DeleteNodeGroup(auth,nodegroupname)
702 traceback.print_exc()
706 def all_hostnames (self) :
708 for site_spec in self.plc_spec['sites']:
709 hostnames += [ node_spec['node_fields']['hostname'] \
710 for node_spec in site_spec['nodes'] ]
713 # silent_minutes : during the first <silent_minutes> minutes nothing gets printed
714 def nodes_check_boot_state (self, target_boot_state, timeout_minutes, silent_minutes,period=15):
715 if self.options.dry_run:
719 timeout = datetime.datetime.now()+datetime.timedelta(minutes=timeout_minutes)
720 graceout = datetime.datetime.now()+datetime.timedelta(minutes=silent_minutes)
721 # the nodes that haven't checked yet - start with a full list and shrink over time
722 tocheck = self.all_hostnames()
723 utils.header("checking nodes %r"%tocheck)
724 # create a dict hostname -> status
725 status = dict ( [ (hostname,'undef') for hostname in tocheck ] )
728 tocheck_status=self.apiserver.GetNodes(self.auth_root(), tocheck, ['hostname','boot_state' ] )
730 for array in tocheck_status:
731 hostname=array['hostname']
732 boot_state=array['boot_state']
733 if boot_state == target_boot_state:
734 utils.header ("%s has reached the %s state"%(hostname,target_boot_state))
736 # if it's a real node, never mind
737 (site_spec,node_spec)=self.locate_hostname(hostname)
738 if TestNode.is_real_model(node_spec['node_fields']['model']):
739 utils.header("WARNING - Real node %s in %s - ignored"%(hostname,boot_state))
741 boot_state = target_boot_state
742 elif datetime.datetime.now() > graceout:
743 utils.header ("%s still in '%s' state"%(hostname,boot_state))
744 graceout=datetime.datetime.now()+datetime.timedelta(1)
745 status[hostname] = boot_state
747 tocheck = [ hostname for (hostname,boot_state) in status.iteritems() if boot_state != target_boot_state ]
750 if datetime.datetime.now() > timeout:
751 for hostname in tocheck:
752 utils.header("FAILURE due to %s in '%s' state"%(hostname,status[hostname]))
754 # otherwise, sleep for a while
756 # only useful in empty plcs
759 def nodes_booted(self):
760 return self.nodes_check_boot_state('boot',timeout_minutes=20,silent_minutes=15)
762 def check_nodes_ssh(self,debug,timeout_minutes,silent_minutes,period=20):
764 timeout = datetime.datetime.now()+datetime.timedelta(minutes=timeout_minutes)
765 graceout = datetime.datetime.now()+datetime.timedelta(minutes=silent_minutes)
766 vservername=self.vservername
769 local_key = "keys/%(vservername)s-debug.rsa"%locals()
772 local_key = "keys/%(vservername)s.rsa"%locals()
773 tocheck = self.all_hostnames()
774 utils.header("checking ssh access (expected in %s mode) to nodes %r"%(message,tocheck))
775 utils.header("max timeout is %d minutes, silent for %d minutes (period is %s)"%\
776 (timeout_minutes,silent_minutes,period))
778 for hostname in tocheck:
779 # try to run 'hostname' in the node
780 command = TestSsh (hostname,key=local_key).actual_command("hostname;uname -a")
781 # don't spam logs - show the command only after the grace period
782 if datetime.datetime.now() > graceout:
783 success=utils.system(command)
785 # truly silent, just print out a dot to show we're alive
788 command += " 2>/dev/null"
789 if self.options.dry_run:
790 print 'dry_run',command
793 success=os.system(command)
795 utils.header('Successfully entered root@%s (%s)'%(hostname,message))
797 tocheck.remove(hostname)
799 # we will have tried real nodes once, in case they're up - but if not, just skip
800 (site_spec,node_spec)=self.locate_hostname(hostname)
801 if TestNode.is_real_model(node_spec['node_fields']['model']):
802 utils.header ("WARNING : check ssh access into real node %s - skipped"%hostname)
803 tocheck.remove(hostname)
806 if datetime.datetime.now() > timeout:
807 for hostname in tocheck:
808 utils.header("FAILURE to ssh into %s"%hostname)
810 # otherwise, sleep for a while
812 # only useful in empty plcs
815 def nodes_ssh_debug(self):
816 return self.check_nodes_ssh(debug=True,timeout_minutes=30,silent_minutes=10)
818 def nodes_ssh_boot(self):
819 return self.check_nodes_ssh(debug=False,timeout_minutes=30,silent_minutes=10)
822 def init_node (self): pass
824 def bootcd (self): pass
826 def configure_qemu (self): pass
828 def reinstall_node (self): pass
830 def export_qemu (self): pass
832 ### check sanity : invoke scripts from qaapi/qa/tests/{node,slice}
833 def check_sanity_node (self):
834 return self.locate_first_node().check_sanity()
835 def check_sanity_sliver (self) :
836 return self.locate_first_sliver().check_sanity()
838 def check_sanity (self):
839 return self.check_sanity_node() and self.check_sanity_sliver()
842 def do_check_initscripts(self):
844 for slice_spec in self.plc_spec['slices']:
845 if not slice_spec.has_key('initscriptname'):
847 initscript=slice_spec['initscriptname']
848 for nodename in slice_spec['nodenames']:
849 (site,node) = self.locate_node (nodename)
850 # xxx - passing the wrong site - probably harmless
851 test_site = TestSite (self,site)
852 test_slice = TestSlice (self,test_site,slice_spec)
853 test_node = TestNode (self,test_site,node)
854 test_sliver = TestSliver (self, test_node, test_slice)
855 if not test_sliver.check_initscript(initscript):
859 def check_initscripts(self):
860 return self.do_check_initscripts()
862 def initscripts (self):
863 for initscript in self.plc_spec['initscripts']:
864 utils.pprint('Adding Initscript in plc %s'%self.plc_spec['name'],initscript)
865 self.apiserver.AddInitScript(self.auth_root(),initscript['initscript_fields'])
868 def clean_initscripts (self):
869 for initscript in self.plc_spec['initscripts']:
870 initscript_name = initscript['initscript_fields']['name']
871 print('Attempting to delete %s in plc %s'%(initscript_name,self.plc_spec['name']))
873 self.apiserver.DeleteInitScript(self.auth_root(),initscript_name)
874 print initscript_name,'deleted'
876 print 'deletion went wrong - probably did not exist'
881 return self.do_slices()
883 def clean_slices (self):
884 return self.do_slices("delete")
886 def do_slices (self, action="add"):
887 for slice in self.plc_spec['slices']:
888 site_spec = self.locate_site (slice['sitename'])
889 test_site = TestSite(self,site_spec)
890 test_slice=TestSlice(self,test_site,slice)
892 utils.header("Deleting slices in site %s"%test_site.name())
893 test_slice.delete_slice()
895 utils.pprint("Creating slice",slice)
896 test_slice.create_slice()
897 utils.header('Created Slice %s'%slice['slice_fields']['name'])
900 @slice_mapper_options
901 def check_slice(self): pass
904 def clear_known_hosts (self): pass
907 def start_node (self) : pass
909 def check_tcp (self):
910 specs = self.plc_spec['tcp_test']
915 s_test_sliver = self.locate_sliver_obj (spec['server_node'],spec['server_slice'])
916 if not s_test_sliver.run_tcp_server(port,timeout=10):
920 # idem for the client side
921 c_test_sliver = self.locate_sliver_obj(spec['server_node'],spec['server_slice'])
922 if not c_test_sliver.run_tcp_client(s_test_sliver.test_node.name(),port):
926 def plcsh_stress_test (self):
927 # install the stress-test in the plc image
928 location = "/usr/share/plc_api/plcsh-stress-test.py"
929 remote="/vservers/%s/%s"%(self.vservername,location)
930 self.test_ssh.copy_abs("plcsh-stress-test.py",remote)
932 command += " -- --check"
933 if self.options.size == 1:
935 return ( self.run_in_guest(command) == 0)
937 def gather_logs (self):
938 # (1.a) get the plc's /var/log/ and store it locally in logs/myplc.var-log.<plcname>/*
939 # (1.b) get the plc's /var/lib/pgsql/data/pg_log/ -> logs/myplc.pgsql-log.<plcname>/*
940 # (2) get all the nodes qemu log and store it as logs/node.qemu.<node>.log
941 # (3) get the nodes /var/log and store is as logs/node.var-log.<node>/*
942 # (4) as far as possible get the slice's /var/log as logs/sliver.var-log.<sliver>/*
944 print "-------------------- TestPlc.gather_logs : PLC's /var/log"
945 self.gather_var_logs ()
947 print "-------------------- TestPlc.gather_logs : PLC's /var/lib/psql/data/pg_log/"
948 self.gather_pgsql_logs ()
950 print "-------------------- TestPlc.gather_logs : nodes's QEMU logs"
951 for site_spec in self.plc_spec['sites']:
952 test_site = TestSite (self,site_spec)
953 for node_spec in site_spec['nodes']:
954 test_node=TestNode(self,test_site,node_spec)
955 test_node.gather_qemu_logs()
957 print "-------------------- TestPlc.gather_logs : nodes's /var/log"
958 self.gather_nodes_var_logs()
960 print "-------------------- TestPlc.gather_logs : sample sliver's /var/log"
961 self.gather_slivers_var_logs()
964 def gather_slivers_var_logs(self):
965 for test_sliver in self.all_sliver_objs():
966 remote = test_sliver.tar_var_logs()
967 utils.system("mkdir -p logs/sliver.var-log.%s"%test_sliver.name())
968 command = remote + " | tar -C logs/sliver.var-log.%s -xf -"%test_sliver.name()
969 utils.system(command)
972 def gather_var_logs (self):
973 utils.system("mkdir -p logs/myplc.var-log.%s"%self.name())
974 to_plc = self.actual_command_in_guest("tar -C /var/log/ -cf - .")
975 command = to_plc + "| tar -C logs/myplc.var-log.%s -xf -"%self.name()
976 utils.system(command)
977 command = "chmod a+r,a+x logs/myplc.var-log.%s/httpd"%self.name()
978 utils.system(command)
980 def gather_pgsql_logs (self):
981 utils.system("mkdir -p logs/myplc.pgsql-log.%s"%self.name())
982 to_plc = self.actual_command_in_guest("tar -C /var/lib/pgsql/data/pg_log/ -cf - .")
983 command = to_plc + "| tar -C logs/myplc.pgsql-log.%s -xf -"%self.name()
984 utils.system(command)
986 def gather_nodes_var_logs (self):
987 for site_spec in self.plc_spec['sites']:
988 test_site = TestSite (self,site_spec)
989 for node_spec in site_spec['nodes']:
990 test_node=TestNode(self,test_site,node_spec)
991 test_ssh = TestSsh (test_node.name(),key="/etc/planetlab/root_ssh_key.rsa")
992 to_plc = self.actual_command_in_guest ( test_ssh.actual_command("tar -C /var/log -cf - ."))
993 command = to_plc + "| tar -C logs/node.var-log.%s -xf -"%test_node.name()
994 utils.system("mkdir -p logs/node.var-log.%s"%test_node.name())
995 utils.system(command)
998 # returns the filename to use for sql dump/restore, using options.dbname if set
999 def dbfile (self, database):
1000 # uses options.dbname if it is found
1002 name=self.options.dbname
1003 if not isinstance(name,StringTypes):
1006 t=datetime.datetime.now()
1009 return "/root/%s-%s.sql"%(database,name)
1012 dump=self.dbfile("planetab4")
1013 self.run_in_guest('pg_dump -U pgsqluser planetlab4 -f '+ dump)
1014 utils.header('Dumped planetlab4 database in %s'%dump)
1017 def db_restore(self):
1018 dump=self.dbfile("planetab4")
1019 ##stop httpd service
1020 self.run_in_guest('service httpd stop')
1021 # xxx - need another wrapper
1022 self.run_in_guest_piped('echo drop database planetlab4','psql --user=pgsqluser template1')
1023 self.run_in_guest('createdb -U postgres --encoding=UNICODE --owner=pgsqluser planetlab4')
1024 self.run_in_guest('psql -U pgsqluser planetlab4 -f '+dump)
1025 ##starting httpd service
1026 self.run_in_guest('service httpd start')
1028 utils.header('Database restored from ' + dump)
1031 def standby_1(): pass
1033 def standby_2(): pass
1035 def standby_3(): pass
1037 def standby_4(): pass
1039 def standby_5(): pass
1041 def standby_6(): pass
1043 def standby_7(): pass
1045 def standby_8(): pass
1047 def standby_9(): pass
1049 def standby_10(): pass
1051 def standby_11(): pass
1053 def standby_12(): pass
1055 def standby_13(): pass
1057 def standby_14(): pass
1059 def standby_15(): pass
1061 def standby_16(): pass
1063 def standby_17(): pass
1065 def standby_18(): pass
1067 def standby_19(): pass
1069 def standby_20(): pass