9 from types import StringTypes
12 from TestSite import TestSite
13 from TestNode import TestNode
14 from TestUser import TestUser
15 from TestKey import TestKey
16 from TestSlice import TestSlice
17 from TestSliver import TestSliver
18 from TestBox import TestBox
19 from TestSsh import TestSsh
21 # step methods must take (self, options) and return a boolean
24 utils.header('Entering StandBy for %d mn'%minutes)
25 time.sleep(60*minutes)
28 def standby_generic (func):
29 def actual(self,options):
30 minutes=int(func.__name__.split("_")[1])
31 return standby(minutes)
36 def __init__ (self,plc_spec,options):
37 self.plc_spec=plc_spec
39 self.test_ssh=TestSsh(self.plc_spec['hostname'],self.options.buildname)
41 self.vserverip=plc_spec['vserverip']
42 self.vservername=plc_spec['vservername']
43 self.url="https://%s:443/PLCAPI/"%plc_spec['vserverip']
47 self.url="https://%s:443/PLCAPI/"%plc_spec['hostname']
48 # utils.header('Using API url %s'%self.url)
49 self.server=xmlrpclib.Server(self.url,allow_none=True)
52 name=self.plc_spec['name']
54 return name+"[%s]"%self.vservername
56 return name+"[chroot]"
59 return self.plc_spec['hostname']
62 return self.test_ssh.is_local()
64 # define the API methods on this object through xmlrpc
65 # would help, but not strictly necessary
69 def run_in_guest (self,command):
70 return self.test_ssh.run(self.host_to_guest(command))
72 def run_in_host (self,command):
73 return self.test_ssh.run_in_buildname(command)
75 #command gets run in the chroot/vserver
76 def host_to_guest(self,command):
78 return "vserver %s exec %s"%(self.vservername,command)
80 return "chroot /plc/root %s"%TestSsh.backslash_shell_specials(command)
82 # copy a file to the myplc root image - pass in_data=True if the file must go in /plc/data
83 def copy_in_guest (self, localfile, remotefile, in_data=False):
85 chroot_dest="/plc/data"
87 chroot_dest="/plc/root"
90 utils.system("cp %s %s/%s"%(localfile,chroot_dest,remotefile))
92 utils.system("cp %s /vservers/%s/%s"%(localfile,self.vservername,remotefile))
95 utils.system("scp %s %s:%s/%s"%(localfile,self.hostname(),chroot_dest,remotefile))
97 utils.system("scp %s %s@/vservers/%s/%s"%(localfile,self.hostname(),self.vservername,remotefile))
101 def run_in_guest_piped (self,local,remote):
102 return utils.system(local+" | "+self.test_ssh.actual_command(self.host_to_guest(remote)))
104 def auth_root (self):
105 return {'Username':self.plc_spec['PLC_ROOT_USER'],
106 'AuthMethod':'password',
107 'AuthString':self.plc_spec['PLC_ROOT_PASSWORD'],
108 'Role' : self.plc_spec['role']
110 def locate_site (self,sitename):
111 for site in self.plc_spec['sites']:
112 if site['site_fields']['name'] == sitename:
114 if site['site_fields']['login_base'] == sitename:
116 raise Exception,"Cannot locate site %s"%sitename
118 def locate_node (self,nodename):
119 for site in self.plc_spec['sites']:
120 for node in site['nodes']:
121 if node['name'] == nodename:
123 raise Exception,"Cannot locate node %s"%nodename
125 def locate_hostname (self,hostname):
126 for site in self.plc_spec['sites']:
127 for node in site['nodes']:
128 if node['node_fields']['hostname'] == hostname:
130 raise Exception,"Cannot locate hostname %s"%hostname
132 def locate_key (self,keyname):
133 for key in self.plc_spec['keys']:
134 if key['name'] == keyname:
136 raise Exception,"Cannot locate key %s"%keyname
138 # all different hostboxes used in this plc
139 def gather_hostBoxes(self):
140 # maps on sites and nodes, return [ (host_box,test_node) ]
142 for site_spec in self.plc_spec['sites']:
143 test_site = TestSite (self,site_spec)
144 for node_spec in site_spec['nodes']:
145 test_node = TestNode (self, test_site, node_spec)
146 if not test_node.is_real():
147 tuples.append( (test_node.host_box(),test_node) )
148 # transform into a dict { 'host_box' -> [ hostnames .. ] }
150 for (box,node) in tuples:
151 if not result.has_key(box):
154 result[box].append(node)
157 # a step for checking this stuff
158 def showboxes (self,options):
160 for (box,nodes) in self.gather_hostBoxes().iteritems():
161 print box,":"," + ".join( [ node.name() for node in nodes ] )
164 # make this a valid step
165 def kill_all_qemus(self,options):
166 for (box,nodes) in self.gather_hostBoxes().iteritems():
167 # this is the brute force version, kill all qemus on that host box
168 TestBox(box,options.buildname).kill_all_qemus()
171 # make this a valid step
172 def list_all_qemus(self,options):
173 for (box,nodes) in self.gather_hostBoxes().iteritems():
174 # this is the brute force version, kill all qemus on that host box
175 TestBox(box,options.buildname).list_all_qemus()
178 # kill only the right qemus
179 def list_qemus(self,options):
180 for (box,nodes) in self.gather_hostBoxes().iteritems():
181 # the fine-grain version
186 # kill only the right qemus
187 def kill_qemus(self,options):
188 for (box,nodes) in self.gather_hostBoxes().iteritems():
189 # the fine-grain version
194 def clear_ssh_config (self,options):
195 # install local ssh_config file as root's .ssh/config - ssh should be quiet
196 # dir might need creation first
197 self.run_in_guest("mkdir /root/.ssh")
198 self.run_in_guest("chmod 700 /root/.ssh")
199 # this does not work - > redirection somehow makes it until an argument to cat
200 #self.run_in_guest_piped("cat ssh_config","cat > /root/.ssh/config")
201 self.copy_in_guest("ssh_config","/root/.ssh/config",True)
204 #################### step methods
207 def uninstall_chroot(self,options):
208 self.run_in_host('service plc safestop')
209 #####detecting the last myplc version installed and remove it
210 self.run_in_host('rpm -e myplc')
211 ##### Clean up the /plc directory
212 self.run_in_host('rm -rf /plc/data')
213 ##### stop any running vservers
214 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')
217 def uninstall_vserver(self,options):
218 self.run_in_host("vserver --silent %s delete"%self.vservername)
221 def uninstall(self,options):
222 # if there's a chroot-based myplc running, and then a native-based myplc is being deployed
223 # it sounds safer to have the former uninstalled too
224 # now the vserver method cannot be invoked for chroot instances as vservername is required
226 self.uninstall_vserver(options)
227 self.uninstall_chroot(options)
229 self.uninstall_chroot(options)
233 def install_chroot(self,options):
237 def install_vserver(self,options):
238 # we need build dir for vtest-init-vserver
240 # a full path for the local calls
241 build_dir=os.path(sys.argv[0])+"/build"
243 # use a standard name - will be relative to HOME
244 build_dir="options.buildname"
245 # run checkout in any case - would do an update if already exists
246 build_checkout = "svn checkout %s %s"%(options.build_url,build_dir)
247 if self.run_in_host(build_checkout) != 0:
248 raise Exception,"Cannot checkout build dir"
249 # the repo url is taken from myplc-url
250 # with the last two steps (i386/myplc...) removed
251 repo_url = options.myplc_url
252 for level in [ 'rpmname','arch' ]:
253 repo_url = os.path.dirname(repo_url)
254 create_vserver="%s/vtest-init-vserver.sh %s %s -- --interface eth0:%s"%\
255 (build_dir,self.vservername,repo_url,self.vserverip)
256 if self.run_in_host(create_vserver) != 0:
257 raise Exception,"Could not create vserver for %s"%self.vservername
260 def install(self,options):
262 return self.install_vserver(options)
264 return self.install_chroot(options)
267 def cache_rpm(self,url,rpm):
268 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()
269 id = self.run_in_host(cache_fetch)
271 raise Exception,"Could not get rpm from %s"%url
273 def install_rpm_chroot(self,options):
274 url = self.options.myplc_url
275 rpm = os.path.basename(url)
276 self.cache_rpm(url,rpm)
277 utils.header('Installing the : %s'%rpm)
278 self.run_in_host('rpm -Uvh '+rpm)
279 self.run_in_host('service plc mount')
282 def install_rpm_vserver(self,options):
283 self.run_in_guest("yum -y install myplc-native")
286 def install_rpm(self,options):
288 return self.install_rpm_vserver(options)
290 return self.install_rpm_chroot(options)
293 def configure(self,options):
294 tmpname='%s.plc-config-tty'%(self.name())
295 fileconf=open(tmpname,'w')
296 for var in [ 'PLC_NAME',
300 'PLC_MAIL_SUPPORT_ADDRESS',
307 fileconf.write ('e %s\n%s\n'%(var,self.plc_spec[var]))
308 fileconf.write('w\n')
309 fileconf.write('q\n')
311 utils.system('cat %s'%tmpname)
312 self.run_in_guest_piped('cat %s'%tmpname,'plc-config-tty')
313 utils.system('rm %s'%tmpname)
316 # the chroot install is slightly different to this respect
317 def start(self, options):
319 self.run_in_guest('service plc start')
321 self.run_in_host('service plc start')
324 def stop(self, options):
326 self.run_in_guest('service plc stop')
328 self.run_in_host('service plc stop')
331 # could use a TestKey class
332 def store_keys(self, options):
333 for key_spec in self.plc_spec['keys']:
334 TestKey(self,key_spec).store_key()
337 def clean_keys(self, options):
338 utils.system("rm -rf %s/keys/"%os.path(sys.argv[0]))
340 def sites (self,options):
341 return self.do_sites(options)
343 def clean_sites (self,options):
344 return self.do_sites(options,action="delete")
346 def do_sites (self,options,action="add"):
347 for site_spec in self.plc_spec['sites']:
348 test_site = TestSite (self,site_spec)
349 if (action != "add"):
350 utils.header("Deleting site %s in %s"%(test_site.name(),self.name()))
351 test_site.delete_site()
352 # deleted with the site
353 #test_site.delete_users()
356 utils.header("Creating site %s & users in %s"%(test_site.name(),self.name()))
357 test_site.create_site()
358 test_site.create_users()
361 def nodes (self, options):
362 return self.do_nodes(options)
363 def clean_nodes (self, options):
364 return self.do_nodes(options,action="delete")
366 def do_nodes (self, options,action="add"):
367 for site_spec in self.plc_spec['sites']:
368 test_site = TestSite (self,site_spec)
370 utils.header("Deleting nodes in site %s"%test_site.name())
371 for node_spec in site_spec['nodes']:
372 test_node=TestNode(self,test_site,node_spec)
373 utils.header("Deleting %s"%test_node.name())
374 test_node.delete_node()
376 utils.header("Creating nodes for site %s in %s"%(test_site.name(),self.name()))
377 for node_spec in site_spec['nodes']:
378 utils.pprint('Creating node %s'%node_spec,node_spec)
379 test_node = TestNode (self,test_site,node_spec)
380 test_node.create_node ()
383 # create nodegroups if needed, and populate
384 # no need for a clean_nodegroups if we are careful enough
385 def nodegroups (self, options):
386 # 1st pass to scan contents
388 for site_spec in self.plc_spec['sites']:
389 test_site = TestSite (self,site_spec)
390 for node_spec in site_spec['nodes']:
391 test_node=TestNode (self,test_site,node_spec)
392 if node_spec.has_key('nodegroups'):
393 nodegroupnames=node_spec['nodegroups']
394 if isinstance(nodegroupnames,StringTypes):
395 nodegroupnames = [ nodegroupnames ]
396 for nodegroupname in nodegroupnames:
397 if not groups_dict.has_key(nodegroupname):
398 groups_dict[nodegroupname]=[]
399 groups_dict[nodegroupname].append(test_node.name())
400 auth=self.auth_root()
401 for (nodegroupname,group_nodes) in groups_dict.iteritems():
403 self.server.GetNodeGroups(auth,{'name':nodegroupname})[0]
405 self.server.AddNodeGroup(auth,{'name':nodegroupname})
406 for node in group_nodes:
407 self.server.AddNodeToNodeGroup(auth,node,nodegroupname)
410 def all_hostnames (self) :
412 for site_spec in self.plc_spec['sites']:
413 hostnames += [ node_spec['node_fields']['hostname'] \
414 for node_spec in site_spec['nodes'] ]
417 # gracetime : during the first <gracetime> minutes nothing gets printed
418 def do_nodes_booted (self, minutes, gracetime=2):
420 timeout = datetime.datetime.now()+datetime.timedelta(minutes=minutes)
421 graceout = datetime.datetime.now()+datetime.timedelta(minutes=gracetime)
422 # the nodes that haven't checked yet - start with a full list and shrink over time
423 tocheck = self.all_hostnames()
424 utils.header("checking nodes %r"%tocheck)
425 # create a dict hostname -> status
426 status = dict ( [ (hostname,'undef') for hostname in tocheck ] )
429 tocheck_status=self.server.GetNodes(self.auth_root(), tocheck, ['hostname','boot_state' ] )
431 for array in tocheck_status:
432 hostname=array['hostname']
433 boot_state=array['boot_state']
434 if boot_state == 'boot':
435 utils.header ("%s has reached the 'boot' state"%hostname)
437 # if it's a real node, never mind
438 (site_spec,node_spec)=self.locate_hostname(hostname)
439 if TestNode.is_real_model(node_spec['node_fields']['model']):
440 utils.header("WARNING - Real node %s in %s - ignored"%(hostname,boot_state))
443 if datetime.datetime.now() > graceout:
444 utils.header ("%s still in '%s' state"%(hostname,boot_state))
445 graceout=datetime.datetime.now()+datetime.timedelta(1)
446 status[hostname] = boot_state
448 tocheck = [ hostname for (hostname,boot_state) in status.iteritems() if boot_state != 'boot' ]
451 if datetime.datetime.now() > timeout:
452 for hostname in tocheck:
453 utils.header("FAILURE due to %s in '%s' state"%(hostname,status[hostname]))
455 # otherwise, sleep for a while
457 # only useful in empty plcs
460 def nodes_booted(self,options):
461 return self.do_nodes_booted(minutes=0)
463 #to scan and store the nodes's public keys and avoid to ask for confirmation when ssh
464 def scan_publicKeys(self,hostnames):
466 temp_knownhosts="/root/known_hosts"
467 remote_knownhosts="/root/.ssh/known_hosts"
468 self.run_in_host("touch %s"%temp_knownhosts )
469 for hostname in hostnames:
470 utils.header("Scan Public %s key and store it in the known_host file(under the root image) "%hostname)
471 scan=self.run_in_host('ssh-keyscan -t rsa %s >> %s '%(hostname,temp_knownhosts))
472 #Store the public keys in the right root image
473 self.copy_in_guest(temp_knownhosts,remote_knownhosts,True)
474 #clean the temp keys file used
475 self.run_in_host('rm -f %s '%temp_knownhosts )
476 except Exception, err:
479 def do_check_nodesSsh(self,minutes):
481 timeout = datetime.datetime.now()+datetime.timedelta(minutes=minutes)
482 tocheck = self.all_hostnames()
483 self.scan_publicKeys(tocheck)
484 utils.header("checking Connectivity on nodes %r"%tocheck)
486 for hostname in tocheck:
487 # try to ssh in nodes
488 access=self.run_in_guest('ssh -o StrictHostKeyChecking=no -o BatchMode=yes -i /etc/planetlab/root_ssh_key.rsa root@%s date'%hostname )
490 utils.header('The node %s is sshable -->'%hostname)
492 tocheck.remove(hostname)
494 (site_spec,node_spec)=self.locate_hostname(hostname)
495 if TestNode.is_real_model(node_spec['node_fields']['model']):
496 utils.header ("WARNING : check ssh access into real node %s - skipped"%hostname)
497 tocheck.remove(hostname)
500 if datetime.datetime.now() > timeout:
501 for hostname in tocheck:
502 utils.header("FAILURE to ssh into %s"%hostname)
504 # otherwise, sleep for a while
506 # only useful in empty plcs
509 def nodes_ssh(self, options):
510 return self.do_check_nodesSsh(minutes=2)
512 def bootcd (self, options):
513 for site_spec in self.plc_spec['sites']:
514 test_site = TestSite (self,site_spec)
515 for node_spec in site_spec['nodes']:
516 test_node=TestNode (self,test_site,node_spec)
517 test_node.prepare_area()
518 test_node.create_boot_cd()
519 test_node.configure_qemu()
522 def do_check_initscripts(self):
523 for site_spec in self.plc_spec['sites']:
524 test_site = TestSite (self,site_spec)
525 test_node = TestNode (self,test_site,site_spec['nodes'])
526 for slice_spec in self.plc_spec['slices']:
527 test_slice=TestSlice (self,test_site,slice_spec)
528 test_sliver=TestSliver(self,test_node,test_slice)
529 init_status=test_sliver.get_initscript(slice_spec)
530 if (not init_status):
534 def check_initscripts(self, options):
535 return self.do_check_initscripts()
537 def initscripts (self, options):
538 for initscript in self.plc_spec['initscripts']:
539 utils.pprint('Adding Initscript in plc %s'%self.plc_spec['name'],initscript)
540 self.server.AddInitScript(self.auth_root(),initscript['initscript_fields'])
543 def slices (self, options):
544 return self.do_slices()
546 def clean_slices (self, options):
547 return self.do_slices("delete")
549 def do_slices (self, action="add"):
550 for slice in self.plc_spec['slices']:
551 site_spec = self.locate_site (slice['sitename'])
552 test_site = TestSite(self,site_spec)
553 test_slice=TestSlice(self,test_site,slice)
555 utils.header("Deleting slices in site %s"%test_site.name())
556 test_slice.delete_slice()
558 utils.pprint("Creating slice",slice)
559 test_slice.create_slice()
560 utils.header('Created Slice %s'%slice['slice_fields']['name'])
563 def check_slices(self, options):
564 for slice_spec in self.plc_spec['slices']:
565 site_spec = self.locate_site (slice_spec['sitename'])
566 test_site = TestSite(self,site_spec)
567 test_slice=TestSlice(self,test_site,slice_spec)
568 status=test_slice.do_check_slice(options)
573 def start_nodes (self, options):
574 utils.header("Starting nodes")
575 for site_spec in self.plc_spec['sites']:
576 TestSite(self,site_spec).start_nodes (options)
579 def stop_nodes (self, options):
580 self.kill_all_qemus(options)
583 def check_tcp (self, options):
584 # we just need to create a sliver object nothing else
585 test_sliver=TestSliver(self,
586 TestNode(self, TestSite(self,self.plc_spec['sites'][0]),
587 self.plc_spec['sites'][0]['nodes'][0]),
588 TestSlice(self,TestSite(self,self.plc_spec['sites'][0]),
589 self.plc_spec['slices']))
590 return test_sliver.do_check_tcp(self.plc_spec['tcp_param'],options)
592 # returns the filename to use for sql dump/restore, using options.dbname if set
593 def dbfile (self, database, options):
594 # uses options.dbname if it is found
597 if not isinstance(name,StringTypes):
600 t=datetime.datetime.now()
603 return "/root/%s-%s.sql"%(database,name)
605 def db_dump(self, options):
607 dump=self.dbfile("planetab4",options)
608 self.run_in_guest('pg_dump -U pgsqluser planetlab4 -f '+ dump)
609 utils.header('Dumped planetlab4 database in %s'%dump)
612 def db_restore(self, options):
613 dump=self.dbfile("planetab4",options)
615 self.run_in_guest('service httpd stop')
616 # xxx - need another wrapper
617 self.run_in_guest_piped('echo drop database planetlab4','psql --user=pgsqluser template1')
618 self.run_in_guest('createdb -U postgres --encoding=UNICODE --owner=pgsqluser planetlab4')
619 self.run_in_guest('psql -U pgsqluser planetlab4 -f '+dump)
620 ##starting httpd service
621 self.run_in_guest('service httpd start')
623 utils.header('Database restored from ' + dump)
626 def standby_1(): pass
628 def standby_2(): pass
630 def standby_3(): pass
632 def standby_4(): pass
634 def standby_5(): pass
636 def standby_6(): pass
638 def standby_7(): pass
640 def standby_8(): pass
642 def standby_9(): pass
644 def standby_10(): pass
646 def standby_11(): pass
648 def standby_12(): pass
650 def standby_13(): pass
652 def standby_14(): pass
654 def standby_15(): pass
656 def standby_16(): pass
658 def standby_17(): pass
660 def standby_18(): pass
662 def standby_19(): pass
664 def standby_20(): pass