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):
37 self.plc_spec=plc_spec
38 self.path=os.path.dirname(sys.argv[0])
39 self.test_ssh=TestSsh(self.plc_spec['hostname'],self.path)
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 full_command(self,command):
70 return self.test_ssh.to_host(self.host_to_guest(command))
72 def run_in_guest (self,command):
73 return utils.system(self.full_command(command))
75 def run_in_host (self,command):
76 return utils.system(self.test_ssh.to_host(command))
78 #command gets run in the chroot/vserver
79 def host_to_guest(self,command):
81 return "vserver %s exec %s"%(self.vservername,command)
83 return "chroot /plc/root %s"%TestSsh.backslash_shell_specials(command)
85 # copy a file to the myplc root image - pass in_data=True if the file must go in /plc/data
86 def copy_in_guest (self, localfile, remotefile, in_data=False):
88 chroot_dest="/plc/data"
90 chroot_dest="/plc/root"
93 utils.system("cp %s %s/%s"%(localfile,chroot_dest,remotefile))
95 utils.system("cp %s /vservers/%s/%s"%(localfile,self.vservername,remotefile))
98 utils.system("scp %s %s:%s/%s"%(localfile,self.hostname(),chroot_dest,remotefile))
100 utils.system("scp %s %s@/vservers/%s/%s"%(localfile,self.hostname(),self.vservername,remotefile))
104 def run_in_guest_piped (self,local,remote):
105 return utils.system(local+" | "+self.full_command(remote))
108 def auth_root (self):
109 return {'Username':self.plc_spec['PLC_ROOT_USER'],
110 'AuthMethod':'password',
111 'AuthString':self.plc_spec['PLC_ROOT_PASSWORD'],
112 'Role' : self.plc_spec['role']
114 def locate_site (self,sitename):
115 for site in self.plc_spec['sites']:
116 if site['site_fields']['name'] == sitename:
118 if site['site_fields']['login_base'] == sitename:
120 raise Exception,"Cannot locate site %s"%sitename
122 def locate_node (self,nodename):
123 for site in self.plc_spec['sites']:
124 for node in site['nodes']:
125 if node['name'] == nodename:
127 raise Exception,"Cannot locate node %s"%nodename
129 def locate_hostname (self,hostname):
130 for site in self.plc_spec['sites']:
131 for node in site['nodes']:
132 if node['node_fields']['hostname'] == hostname:
134 raise Exception,"Cannot locate hostname %s"%hostname
136 def locate_key (self,keyname):
137 for key in self.plc_spec['keys']:
138 if key['name'] == keyname:
140 raise Exception,"Cannot locate key %s"%keyname
142 # all different hostboxes used in this plc
143 def gather_hostBoxes(self):
144 # maps on sites and nodes, return [ (host_box,test_node) ]
146 for site_spec in self.plc_spec['sites']:
147 test_site = TestSite (self,site_spec)
148 for node_spec in site_spec['nodes']:
149 test_node = TestNode (self, test_site, node_spec)
150 if not test_node.is_real():
151 tuples.append( (test_node.host_box(),test_node) )
152 # transform into a dict { 'host_box' -> [ hostnames .. ] }
154 for (box,node) in tuples:
155 if not result.has_key(box):
158 result[box].append(node)
161 # a step for checking this stuff
162 def showboxes (self,options):
164 for (box,nodes) in self.gather_hostBoxes().iteritems():
165 print box,":"," + ".join( [ node.name() for node in nodes ] )
168 # make this a valid step
169 def kill_all_qemus(self,options):
170 for (box,nodes) in self.gather_hostBoxes().iteritems():
171 # this is the brute force version, kill all qemus on that host box
172 TestBox(box,options.buildname).kill_all_qemus()
175 # make this a valid step
176 def list_all_qemus(self,options):
177 for (box,nodes) in self.gather_hostBoxes().iteritems():
178 # this is the brute force version, kill all qemus on that host box
179 TestBox(box,options.buildname).list_all_qemus()
182 # kill only the right qemus
183 def list_qemus(self,options):
184 for (box,nodes) in self.gather_hostBoxes().iteritems():
185 # the fine-grain version
190 # kill only the right qemus
191 def kill_qemus(self,options):
192 for (box,nodes) in self.gather_hostBoxes().iteritems():
193 # the fine-grain version
198 def clear_ssh_config (self,options):
199 # install local ssh_config file as root's .ssh/config - ssh should be quiet
200 # dir might need creation first
201 self.run_in_guest("mkdir /root/.ssh")
202 self.run_in_guest("chmod 700 /root/.ssh")
203 # this does not work - > redirection somehow makes it until an argument to cat
204 #self.run_in_guest_piped("cat ssh_config","cat > /root/.ssh/config")
205 self.copy_in_guest("ssh_config","/root/.ssh/config",True)
208 #################### step methods
211 def uninstall_chroot(self,options):
212 self.run_in_host('service plc safestop')
213 #####detecting the last myplc version installed and remove it
214 self.run_in_host('rpm -e myplc')
215 ##### Clean up the /plc directory
216 self.run_in_host('rm -rf /plc/data')
217 ##### stop any running vservers
218 self.run_in_host('for vserver in $(ls /vservers/* | sed -e s,/vservers/,,) ; do vserver $vserver stop ; done')
221 def uninstall_vserver(self,options):
222 self.run_in_host("vserver --silent %s delete"%self.vservername)
225 def uninstall(self,options):
226 # if there's a chroot-based myplc running, and then a native-based myplc is being deployed
227 # it sounds safer to have the former uninstalled too
228 # now the vserver method cannot be invoked for chroot instances as vservername is required
230 self.uninstall_vserver(options)
231 self.uninstall_chroot(options)
233 self.uninstall_chroot(options)
237 def install_chroot(self,options):
241 def install_vserver(self,options):
242 # we need build dir for vtest-init-vserver
244 # a full path for the local calls
245 build_dir=self.path+"/build"
247 # use a standard name - will be relative to HOME
248 build_dir="options.buildname"
249 # run checkout in any case - would do an update if already exists
250 build_checkout = "svn checkout %s %s"%(options.build_url,build_dir)
251 if self.run_in_host(build_checkout) != 0:
252 raise Exception,"Cannot checkout build dir"
253 # the repo url is taken from myplc-url
254 # with the last two steps (i386/myplc...) removed
255 repo_url = options.myplc_url
256 for level in [ 'rpmname','arch' ]:
257 repo_url = os.path.dirname(repo_url)
258 create_vserver="%s/vtest-init-vserver.sh %s %s -- --interface eth0:%s"%\
259 (build_dir,self.vservername,repo_url,self.vserverip)
260 if self.run_in_host(create_vserver) != 0:
261 raise Exception,"Could not create vserver for %s"%self.vservername
264 def install(self,options):
266 return self.install_vserver(options)
268 return self.install_chroot(options)
271 def cache_rpm(self,url):
272 self.run_in_host('rm -rf *.rpm')
273 utils.header('Curling rpm from %s'%url)
274 id= self.run_in_host('curl -O '+url)
276 raise Exception,"Could not get rpm from %s"%url
280 def install_rpm_chroot(self,options):
281 rpm = os.path.basename(options.myplc_url)
282 if (not os.path.isfile(rpm)):
283 self.cache_rpm(options.myplc_url)
284 utils.header('Installing the : %s'%rpm)
285 self.run_in_host('rpm -Uvh '+rpm)
286 self.run_in_host('service plc mount')
289 def install_rpm_vserver(self,options):
290 self.run_in_guest("yum -y install myplc-native")
293 def install_rpm(self,options):
295 return self.install_rpm_vserver(options)
297 return self.install_rpm_chroot(options)
300 def configure(self,options):
301 tmpname='%s.plc-config-tty'%(self.name())
302 fileconf=open(tmpname,'w')
303 for var in [ 'PLC_NAME',
307 'PLC_MAIL_SUPPORT_ADDRESS',
314 fileconf.write ('e %s\n%s\n'%(var,self.plc_spec[var]))
315 fileconf.write('w\n')
316 fileconf.write('q\n')
318 utils.system('cat %s'%tmpname)
319 self.run_in_guest_piped('cat %s'%tmpname,'plc-config-tty')
320 utils.system('rm %s'%tmpname)
323 # the chroot install is slightly different to this respect
324 def start(self, options):
326 self.run_in_guest('service plc start')
328 self.run_in_host('service plc start')
331 def stop(self, options):
333 self.run_in_guest('service plc stop')
335 self.run_in_host('service plc stop')
338 # could use a TestKey class
339 def store_keys(self, options):
340 for key_spec in self.plc_spec['keys']:
341 TestKey(self,key_spec).store_key()
344 def clean_keys(self, options):
345 utils.system("rm -rf %s/keys/"%self.path)
347 def sites (self,options):
348 return self.do_sites(options)
350 def clean_sites (self,options):
351 return self.do_sites(options,action="delete")
353 def do_sites (self,options,action="add"):
354 for site_spec in self.plc_spec['sites']:
355 test_site = TestSite (self,site_spec)
356 if (action != "add"):
357 utils.header("Deleting site %s in %s"%(test_site.name(),self.name()))
358 test_site.delete_site()
359 # deleted with the site
360 #test_site.delete_users()
363 utils.header("Creating site %s & users in %s"%(test_site.name(),self.name()))
364 test_site.create_site()
365 test_site.create_users()
368 def nodes (self, options):
369 return self.do_nodes(options)
370 def clean_nodes (self, options):
371 return self.do_nodes(options,action="delete")
373 def do_nodes (self, options,action="add"):
374 for site_spec in self.plc_spec['sites']:
375 test_site = TestSite (self,site_spec)
377 utils.header("Deleting nodes in site %s"%test_site.name())
378 for node_spec in site_spec['nodes']:
379 test_node=TestNode(self,test_site,node_spec)
380 utils.header("Deleting %s"%test_node.name())
381 test_node.delete_node()
383 utils.header("Creating nodes for site %s in %s"%(test_site.name(),self.name()))
384 for node_spec in site_spec['nodes']:
385 utils.pprint('Creating node %s'%node_spec,node_spec)
386 test_node = TestNode (self,test_site,node_spec)
387 test_node.create_node ()
390 # create nodegroups if needed, and populate
391 # no need for a clean_nodegroups if we are careful enough
392 def nodegroups (self, options):
393 # 1st pass to scan contents
395 for site_spec in self.plc_spec['sites']:
396 test_site = TestSite (self,site_spec)
397 for node_spec in site_spec['nodes']:
398 test_node=TestNode (self,test_site,node_spec)
399 if node_spec.has_key('nodegroups'):
400 nodegroupnames=node_spec['nodegroups']
401 if isinstance(nodegroupnames,StringTypes):
402 nodegroupnames = [ nodegroupnames ]
403 for nodegroupname in nodegroupnames:
404 if not groups_dict.has_key(nodegroupname):
405 groups_dict[nodegroupname]=[]
406 groups_dict[nodegroupname].append(test_node.name())
407 auth=self.auth_root()
408 for (nodegroupname,group_nodes) in groups_dict.iteritems():
410 self.server.GetNodeGroups(auth,{'name':nodegroupname})[0]
412 self.server.AddNodeGroup(auth,{'name':nodegroupname})
413 for node in group_nodes:
414 self.server.AddNodeToNodeGroup(auth,node,nodegroupname)
417 def all_hostnames (self) :
419 for site_spec in self.plc_spec['sites']:
420 hostnames += [ node_spec['node_fields']['hostname'] \
421 for node_spec in site_spec['nodes'] ]
424 # gracetime : during the first <gracetime> minutes nothing gets printed
425 def do_nodes_booted (self, minutes, gracetime=2):
427 timeout = datetime.datetime.now()+datetime.timedelta(minutes=minutes)
428 graceout = datetime.datetime.now()+datetime.timedelta(minutes=gracetime)
429 # the nodes that haven't checked yet - start with a full list and shrink over time
430 tocheck = self.all_hostnames()
431 utils.header("checking nodes %r"%tocheck)
432 # create a dict hostname -> status
433 status = dict ( [ (hostname,'undef') for hostname in tocheck ] )
436 tocheck_status=self.server.GetNodes(self.auth_root(), tocheck, ['hostname','boot_state' ] )
438 for array in tocheck_status:
439 hostname=array['hostname']
440 boot_state=array['boot_state']
441 if boot_state == 'boot':
442 utils.header ("%s has reached the 'boot' state"%hostname)
444 # if it's a real node, never mind
445 (site_spec,node_spec)=self.locate_hostname(hostname)
446 if TestNode.is_real_model(node_spec['node_fields']['model']):
447 utils.header("WARNING - Real node %s in %s - ignored"%(hostname,boot_state))
450 if datetime.datetime.now() > graceout:
451 utils.header ("%s still in '%s' state"%(hostname,boot_state))
452 graceout=datetime.datetime.now()+datetime.timedelta(1)
453 status[hostname] = boot_state
455 tocheck = [ hostname for (hostname,boot_state) in status.iteritems() if boot_state != 'boot' ]
458 if datetime.datetime.now() > timeout:
459 for hostname in tocheck:
460 utils.header("FAILURE due to %s in '%s' state"%(hostname,status[hostname]))
462 # otherwise, sleep for a while
464 # only useful in empty plcs
467 def nodes_booted(self,options):
468 return self.do_nodes_booted(minutes=0)
470 #to scan and store the nodes's public keys and avoid to ask for confirmation when ssh
471 def scan_publicKeys(self,hostnames):
473 temp_knownhosts="/root/known_hosts"
474 remote_knownhosts="/root/.ssh/known_hosts"
475 self.run_in_host("touch %s"%temp_knownhosts )
476 for hostname in hostnames:
477 utils.header("Scan Public %s key and store it in the known_host file(under the root image) "%hostname)
478 scan=self.run_in_host('ssh-keyscan -t rsa %s >> %s '%(hostname,temp_knownhosts))
479 #Store the public keys in the right root image
480 self.copy_in_guest(temp_knownhosts,remote_knownhosts,True)
481 #clean the temp keys file used
482 self.run_in_host('rm -f %s '%temp_knownhosts )
483 except Exception, err:
486 def do_check_nodesSsh(self,minutes):
488 timeout = datetime.datetime.now()+datetime.timedelta(minutes=minutes)
489 tocheck = self.all_hostnames()
490 self.scan_publicKeys(tocheck)
491 utils.header("checking Connectivity on nodes %r"%tocheck)
493 for hostname in tocheck:
494 # try to ssh in nodes
495 access=self.run_in_guest('ssh -o StrictHostKeyChecking=no -o BatchMode=yes -i /etc/planetlab/root_ssh_key.rsa root@%s date'%hostname )
497 utils.header('The node %s is sshable -->'%hostname)
499 tocheck.remove(hostname)
501 (site_spec,node_spec)=self.locate_hostname(hostname)
502 if TestNode.is_real_model(node_spec['node_fields']['model']):
503 utils.header ("WARNING : check ssh access into real node %s - skipped"%hostname)
504 tocheck.remove(hostname)
507 if datetime.datetime.now() > timeout:
508 for hostname in tocheck:
509 utils.header("FAILURE to ssh into %s"%hostname)
511 # otherwise, sleep for a while
513 # only useful in empty plcs
516 def nodes_ssh(self, options):
517 return self.do_check_nodesSsh(minutes=2)
519 def bootcd (self, options):
520 for site_spec in self.plc_spec['sites']:
521 test_site = TestSite (self,site_spec)
522 for node_spec in site_spec['nodes']:
523 test_node=TestNode (self,test_site,node_spec)
524 test_node.prepare_area()
525 test_node.create_boot_cd()
526 test_node.configure_qemu()
529 def do_check_intiscripts(self):
530 for site_spec in self.plc_spec['sites']:
531 test_site = TestSite (self,site_spec)
532 test_node = TestNode (self,test_site,site_spec['nodes'])
533 for slice_spec in self.plc_spec['slices']:
534 test_slice=TestSlice (self,test_site,slice_spec)
535 test_sliver=TestSliver(self,test_node,test_slice)
536 init_status=test_sliver.get_initscript(slice_spec)
537 if (not init_status):
541 def check_initscripts(self, options):
542 return self.do_check_intiscripts()
544 def initscripts (self, options):
545 for initscript in self.plc_spec['initscripts']:
546 utils.pprint('Adding Initscript in plc %s'%self.plc_spec['name'],initscript)
547 self.server.AddInitScript(self.auth_root(),initscript['initscript_fields'])
550 def slices (self, options):
551 return self.do_slices()
553 def clean_slices (self, options):
554 return self.do_slices("delete")
556 def do_slices (self, action="add"):
557 for slice in self.plc_spec['slices']:
558 site_spec = self.locate_site (slice['sitename'])
559 test_site = TestSite(self,site_spec)
560 test_slice=TestSlice(self,test_site,slice)
562 utils.header("Deleting slices in site %s"%test_site.name())
563 test_slice.delete_slice()
565 utils.pprint("Creating slice",slice)
566 test_slice.create_slice()
567 utils.header('Created Slice %s'%slice['slice_fields']['name'])
570 def check_slices(self, options):
571 for slice_spec in self.plc_spec['slices']:
572 site_spec = self.locate_site (slice_spec['sitename'])
573 test_site = TestSite(self,site_spec)
574 test_slice=TestSlice(self,test_site,slice_spec)
575 status=test_slice.do_check_slice(options)
580 def start_nodes (self, options):
581 utils.header("Starting nodes")
582 for site_spec in self.plc_spec['sites']:
583 TestSite(self,site_spec).start_nodes (options)
586 def stop_nodes (self, options):
587 self.kill_all_qemus(options)
590 def check_tcp (self, options):
591 #we just need to create a sliver object nothing else
592 test_sliver=TestSliver(self,
593 TestNode(self, TestSite(self,self.plc_spec['sites'][0]),
594 self.plc_spec['sites'][0]['nodes'][0]),
595 TestSlice(self,TestSite(self,self.plc_spec['sites'][0]),
596 self.plc_spec['slices']))
597 return test_sliver.do_check_tcp(self.plc_spec['tcp_param'],options)
599 # returns the filename to use for sql dump/restore, using options.dbname if set
600 def dbfile (self, database, options):
601 # uses options.dbname if it is found
604 if not isinstance(name,StringTypes):
607 t=datetime.datetime.now()
610 return "/root/%s-%s.sql"%(database,name)
612 def db_dump(self, options):
614 dump=self.dbfile("planetab4",options)
615 self.run_in_guest('pg_dump -U pgsqluser planetlab4 -f '+ dump)
616 utils.header('Dumped planetlab4 database in %s'%dump)
619 def db_restore(self, options):
620 dump=self.dbfile("planetab4",options)
622 self.run_in_guest('service httpd stop')
623 # xxx - need another wrapper
624 self.run_in_guest_piped('echo drop database planetlab4','psql --user=pgsqluser template1')
625 self.run_in_guest('createdb -U postgres --encoding=UNICODE --owner=pgsqluser planetlab4')
626 self.run_in_guest('psql -U pgsqluser planetlab4 -f '+dump)
627 ##starting httpd service
628 self.run_in_guest('service httpd start')
630 utils.header('Database restored from ' + dump)
633 def standby_1(): pass
635 def standby_2(): pass
637 def standby_3(): pass
639 def standby_4(): pass
641 def standby_5(): pass
643 def standby_6(): pass
645 def standby_7(): pass
647 def standby_8(): pass
649 def standby_9(): pass
651 def standby_10(): pass
653 def standby_11(): pass
655 def standby_12(): pass
657 def standby_13(): pass
659 def standby_14(): pass
661 def standby_15(): pass
663 def standby_16(): pass
665 def standby_17(): pass
667 def standby_18(): pass
669 def standby_19(): pass
671 def standby_20(): pass