merge changes from HEAD
[plcapi.git] / TestPeers.py
1 #!/usr/bin/env python
2 ###
3 ##############################
4 ###
5 ### preparation / requirements
6 ###
7 ### two separate instances of myplc
8 ### for now they are located on the same box on lurch
9 ###
10 ### expectations :
11 ### your myplcs should more or less come out of the box, 
12 ### I prefer not to alter the default PLC_ROOT_USER value,
13 ### instead we create a PI account on the site_id=1
14 ###
15 ##############################
16
17 ### xxx todo
18 # check sites
19 # check persons
20
21 # support reloading without wiping everything off
22 # dunno how to do (defvar plc)
23
24 import getopt
25 import sys
26 import time
27
28 from PLC.Shell import Shell
29 import PLC.Methods
30
31 # when running locally, we might wish to run only our local stuff
32 dummy_print_methods = [ 'RefreshPeer' ]
33 class DummyShell:
34     class Callable:
35         def __init__(self,method,index):
36             self.method=method
37             self.index=index
38             self.printed=False
39         def __call__ (self, *args, **kwds):
40             if not self.printed or self.method in dummy_print_methods:
41                 print "Dummy method %s on remote peer %d skipped"%(self.method,self.index)
42                 self.printed=True
43             return 0
44     def __init__(self,index):
45         self.index=index
46         for method in PLC.Methods.methods:
47             # ignore path-defined methods for now
48             if "." not in method:
49                 setattr(self,method,DummyShell.Callable(method,self.index))
50         
51 ####################
52 #import xmlrpclib
53 import os
54
55 ## try to support reload
56 try:
57     globals()['plc']
58 except:
59     plc=[None,None,None]
60 try:
61     globals()['s']
62 except:
63     s=[None,None,None]
64     
65 ####################
66 # predefined stuff
67 # number of 'system' persons
68 # builtin maint, local root, 2 persons for the peering
69 system_persons = 4
70 # among that, 1 gets refreshed - other ones have conflicting names
71 system_persons_cross = 1
72
73 system_slices_ids = (1,)
74 def system_slices ():
75     return len(system_slices_ids)
76 def total_slices ():
77     return number_slices+system_slices()
78
79 def system_slivers ():
80     return len(system_slices_ids)
81
82 # too tedious to do the maths : how many slices attached to node 1
83 expected_slivers=None
84 def total_slivers ():
85     global expected_slivers
86     if expected_slivers is None:
87         expected_slivers=0
88         actual_nodes_per_slice = min (number_nodes,number_nodes_per_slice)
89         for ns in myrange(number_slices):
90             slice_range = [ map_on_node (n+ns) for n in range(actual_nodes_per_slice)]
91             if 1 in slice_range:
92                 expected_slivers += 1
93     return expected_slivers+system_slivers()
94
95 ####################
96 # set initial conditions
97 # actual persons_per_slice is min(number_persons,number_persons_per_slice)
98 # actual nodes_per_slice is min(number_nodes,number_nodes_per_slice)
99 # this is to prevent quadractic test times on big tests
100 def define_test (sites,persons,nodes,slices,
101                  keys_per_person,nodes_per_slice,persons_per_slice,fast_mode=None):
102     global number_sites, number_persons, number_nodes, number_slices
103     global number_keys_per_person, number_nodes_per_slice, number_persons_per_slice, fast_flag
104     number_sites = sites
105     number_persons=persons
106     number_nodes=nodes
107     number_slices=slices
108     number_keys_per_person=keys_per_person
109     number_nodes_per_slice=nodes_per_slice
110     number_persons_per_slice=persons_per_slice
111     if fast_mode is not None:
112         fast_flag=fast_mode
113
114 # when we run locally on a given peer
115 local_peer=None
116
117 def show_test():
118     print '%d sites, %d persons, %d nodes & %d slices'%(
119         number_sites,number_persons,number_nodes,number_slices)
120     print '%d keys/person, %d nodes/slice & %d persons/slice'%(
121         number_keys_per_person,number_nodes_per_slice,number_persons_per_slice)
122     print 'fast_flag',fast_flag
123     if local_peer is not None:
124         print 'Running locally on index %d'%local_peer
125
126 def mini():
127     define_test(1,1,1,1,1,1,1,True)
128     
129 def normal():
130     define_test (sites=4,persons=4,nodes=5,slices=4,
131                  keys_per_person=2,nodes_per_slice=3,persons_per_slice=6,fast_mode=False)
132
133 def apply_factor (factor):
134     global number_sites, number_persons, number_nodes, number_slices
135     [number_sites, number_persons, number_nodes, number_slices] = \
136                    [factor*x for x in     [number_sites, number_persons, number_nodes, number_slices]]
137                                                                    
138
139 # use only 1 key in this case
140 big_factor=4
141 def big():
142     global number_sites, number_persons, number_nodes, number_slices
143     number_sites=200
144     number_persons=500
145     number_nodes=350
146     number_slices=500
147     global nodes_per_slice
148     nodes_per_slice=3
149     global number_keys_per_person
150     number_keys_per_person=1
151     global number_persons_per_slice
152     number_persons_per_slice=3
153
154 #huge_factor=1000
155 def huge():
156     global number_sites, number_persons, number_nodes, number_slices
157     number_sites=1000
158     number_persons=2000
159     number_nodes=3000
160     number_slices=2000
161     global nodes_per_slice
162     nodes_per_slice=3
163     global number_keys_per_person
164     number_keys_per_person=1
165     global number_persons_per_slice
166     number_persons_per_slice=3
167
168 # use mini test by default in interactive mode
169 mini()
170 #normal()
171
172 ####################
173 # argh, for login_name that doesn't accept digits
174 plain_numbers=['zero','one','two','three','four','five','six','seven','eight','nine','ten',
175                'eleven','twelve','thirteen','fourteen','fifteen','sixteen','seventeen','eighteen','nineteen','twenty']
176 plain_digits=['a','b','c','d','e','f','g','h','i','j']
177 ####################
178 plc[1]={ 'plcname':'Thierry plc1',
179          'hostname':'planetlab-devbox.inria.fr',
180          'url-format':'https://%s:443/PLCAPI/',
181          'builtin-admin-id':'root@plc1.org',
182          'builtin-admin-password':'root',
183          'peer-admin-name':'peer1@planet-lab.org',
184          'peer-admin-password':'peer',
185          'node-format':'n1-%03d.plc1.org',
186          'plainname' : 'one',
187          'site-format':'one%s',
188          'person-format' : 'user1-%d@plc1.org',
189          'key-format':'ssh-rsa 11key4plc11 user%d-key%d',
190          'person-password' : 'password1',
191          'gpg-keyring':'gpg_plc2.pub',
192          'api-cacert':'api_plc2.crt',
193        }
194 plc[2]={ 'plcname':'Thierry plc2',
195          'hostname':'lurch.cs.princeton.edu',
196          'url-format':'https://%s:443/PLCAPI/',
197          'builtin-admin-id':'root@plc2.org',
198          'builtin-admin-password':'root',
199          'peer-admin-name':'peer2@planet-lab.org',
200          'peer-admin-password':'peer',
201          'node-format':'n2-%03d.plc2.org',
202          'plainname' : 'two',
203          'site-format':'two%s',
204          'person-format' : 'user2-%d@plc2.org',
205          'key-format':'ssh-rsa 22key4plc22 user%d-key%d',
206          'person-password' : 'password2',
207          'gpg-keyring':'gpg_plc1.pub',
208          'api-cacert':'api_plc1.crt',
209        }
210
211 ####################
212 def peer_index(i):
213     return 3-i
214
215 def plc_name (i):
216     return plc[i]['plcname']
217
218 def site_name (i,n):
219     x=site_login_base(i,n)
220     return 'Site fullname '+x
221
222 def site_login_base (i,n):
223     # for huge
224     if number_sites<len(plain_numbers):
225         return plc[i]['site-format']%plain_numbers[n]
226     else:
227         string=''
228         while True:
229             quo=n/10
230             rem=n%10
231             string=plain_digits[rem]+string
232             if quo == 0:
233                 break
234             else:
235                 n=quo
236         return plc[i]['site-format']%string
237
238 def person_name (i,n):
239     return plc[i]['person-format']%n
240
241 def key_name (i,n,k):
242     return plc[i]['key-format']%(n,k)
243
244 def node_name (i,n):
245     return plc[i]['node-format']%n
246
247 def slice_name (i,n):
248     site_index=map_on_site(n)
249     return "%s_slice%d"%(site_login_base(i,site_index),n)
250
251 def sat_name (i):
252     return 'sat_%d'%i
253
254 # to have indexes start at 1
255 def map_on (n,max):
256     result=(n%max)
257     if result==0:
258         result=max
259     return result
260
261 def myrange (n):
262     return range (1,n+1,1)
263
264 def map_on_site (n):
265     return map_on (n,number_sites)
266
267 def map_on_person (n):
268     return map_on (n,number_persons)
269
270 def map_on_node (n):
271     return map_on (n,number_nodes)
272
273 def message (*args):
274     print "====================",
275     print args
276     
277 ##########
278 def timer_start ():
279     global epoch,last_time
280     epoch = time.time()
281     last_time=epoch
282     print '+++ timer start'
283
284 def timer_show ():
285     global last_time
286     now=time.time()
287     print '+++ %.02f seconds ellapsed (%.02f)'%(now-epoch,now-last_time)
288     last_time=now
289
290 ####################
291 errors=0
292 def myassert (message,boolean):
293     if not boolean:
294         print 'ASSERTION FAILED',message
295         global errors
296         errors +=1
297
298 def epilogue ():
299     if errors != 0:
300         print 'TEST FAILED with %d errors'%errors
301         assert errors == 0
302         
303 ####################
304 # init
305 def test00_init (args=[1,2],builtin_person=False):
306     timer_start()
307     for i in args:
308         url=plc[i]['url-format']%plc[i]['hostname']
309         plc[i]['url']=url
310         if local_peer is None:
311             # the regular remote mode
312             print 'initializing s[%d]=>%s'%(i,url),
313             if builtin_person:
314                 user=plc[i]['builtin-admin-id']
315                 password=plc[i]['builtin-admin-password']
316             else:
317                 user=plc[i]['peer-admin-name']
318                 password=plc[i]['peer-admin-password']
319             s[i]=Shell(url=url,
320                        user=user,
321                        password=password)
322             print 'user=',user
323         elif local_peer == i:
324             # local mode - use Shell's Direct mode - use /etc/planetlab/plc_config
325             s[i]=Shell()
326         else:
327             # remote peer in local mode : use dummy shell instead
328             s[i]=DummyShell(i)
329
330 # use new person's account
331
332 def test00_print (args=[1,2]):
333     for i in args:
334         print '==================== s[%d]'%i
335 #        s[i].show_config()
336         print 'show_config obsoleted'
337     print '===================='
338
339 def check_nodes (el,ef,args=[1,2]):
340     for i in args:
341         # use a single request and sort afterwards for efficiency
342         # could have used GetNodes's scope as well
343         all_nodes = s[i].GetNodes()
344         n = len ([ x for x in all_nodes if x['peer_id'] is None])
345         f = len ([ x for x in all_nodes if x['peer_id'] is not None])
346         print '%02d: Checking nodes: got %d local (e=%d) & %d foreign (e=%d)'%(i,n,el,f,ef)
347         myassert ('local nodes',n==el)
348         myassert ('foreign nodes',f==ef)
349
350 def check_keys (el,ef,args=[1,2]):
351     for i in args:
352         # use a single request and sort afterwards for efficiency
353         # could have used GetKeys's scope as well
354         all_keys = s[i].GetKeys()
355         n = len ([ x for x in all_keys if x['peer_id'] is None])
356         f = len ([ x for x in all_keys if x['peer_id'] is not None])
357         print '%02d: Checking keys: got %d local (e=%d) & %d foreign (e=%d)'%(i,n,el,f,ef)
358         myassert ('local keys',n==el)
359         myassert ('foreign_keys',f==ef)
360
361 def check_persons (el,ef,args=[1,2]):
362     for i in args:
363         # use a single request and sort afterwards for efficiency
364         # could have used GetPersons's scope as well
365         all_persons = s[i].GetPersons()
366         n = len ([ x for x in all_persons if x['peer_id'] is None])
367         f = len ([ x for x in all_persons if x['peer_id'] is not None])
368         print '%02d: Checking persons: got %d local (e=%d) & %d foreign (e=%d)'%(i,n,el,f,ef)
369         myassert ('local persons',n==el)
370         myassert ('foreign persons',f==ef)
371
372 # expected : local slices, foreign slices
373 def check_slices (els,efs,args=[1,2]):
374     for i in args:
375         ls=len(s[i].GetSlices({'peer_id':None}))
376         fs=len(s[i].GetSlices({'~peer_id':None}))
377         print '%02d: Checking slices: got %d local (e=%d) & %d foreign (e=%d)'%(i,ls,els,fs,efs)
378         myassert ('local slices',els==ls)
379         myassert ('foreign slices',efs==fs)
380
381 def show_nodes (i,node_ids):
382     # same as above
383     all_nodes = s[i].GetNodes(node_ids)
384     loc_nodes = filter (lambda n: n['peer_id'] is None, all_nodes)
385     for_nodes = filter (lambda n: n['peer_id'] is not None, all_nodes)
386
387     for message,nodes in [ ['LOC',loc_nodes], ['FOR',for_nodes] ] :
388         if nodes:
389             print '[%s:%d] : '%(message,len(nodes)),
390             for node in nodes:
391                 print node['hostname']+' ',
392             print ''
393
394 def check_slice_nodes (expected_nodes, is_local_slice, args=[1,2]):
395     for ns in myrange(number_slices):
396         check_slice_nodes_n (ns,expected_nodes, is_local_slice, args)
397
398 def check_slice_nodes_n (ns,expected_nodes, is_local_slice, args=[1,2]):
399     for i in args:
400         peer=peer_index(i)
401         if is_local_slice:
402             sname=slice_name(i,ns)
403             slice=s[i].GetSlices({'name':[sname],'peer_id':None})[0]
404             message='local'
405         else:
406             sname=slice_name(peer,ns)
407             slice=s[i].GetSlices({'name':[sname],'~peer_id':None})[0]
408             message='foreign'
409         print '%02d: %s slice %s (e=%d) '%(i,message,sname,expected_nodes),
410         slice_node_ids=slice['node_ids']
411         print 'on nodes ',slice_node_ids
412         show_nodes (i,slice_node_ids)
413         myassert ('slice nodes',len(slice_node_ids)>=expected_nodes)
414         if len(slice_node_ids) != expected_nodes:
415             print 'TEMPORARY'
416
417 # expected : nodes on local slice
418 def check_local_slice_nodes (expected, args=[1,2]):
419     check_slice_nodes(expected,True,args)
420
421 # expected : nodes on foreign slice
422 def check_foreign_slice_nodes (expected, args=[1,2]):
423     check_slice_nodes(expected,False,args)
424
425 def check_conf_files (args=[1,2]):
426     for nn in myrange(number_nodes):
427         check_conf_files_n (nn,args)
428
429 def check_conf_files_n (nn,args=[1,2]):
430     for i in args:
431         nodename=node_name(i,nn)
432         ndict= s[i].GetSlivers([nodename])[0]
433         myassert ('conf files',ndict['hostname'] == nodename)
434         conf_files = ndict['conf_files']
435         print '%02d: %d conf_files in GetSlivers for node %s'%(i,len(conf_files),nodename)
436         for conf_file in conf_files:
437             print 'source=',conf_file['source'],'|',
438             print 'dest=',conf_file['dest'],'|',
439             print 'enabled=',conf_file['enabled'],'|',
440             print ''
441
442 import pprint
443 pp = pprint.PrettyPrinter(indent=3)
444
445 def check_slivers (esn,args=[1,2]):
446     for nn in myrange(number_nodes):
447         check_slivers_n (nn,esn,args)
448
449 # too verbose to check all nodes, let's check only the first one
450 def check_slivers_1 (esn,args=[1,2]):
451     check_slivers_n (1,esn,args)
452
453 def check_slivers_n (nn,esn,args=[1,2]):
454     for i in args:
455         nodename=node_name(i,nn)
456         ndict= s[i].GetSlivers(nodename)
457         myassert ('slivers hostname',ndict['hostname'] == nodename)
458         slivers = ndict['slivers']
459         print '%02d: %d slivers (exp. %d) in GetSlivers for node %s'\
460               %(i,len(slivers),esn,nodename)
461         for sliver in slivers:
462             print '>>slivername = ',sliver['name']
463             pretty_printer.pprint(sliver)
464         myassert ('slivers count',len(slivers) == esn)
465                 
466
467 ####################
468 def test00_admin_person (args=[1,2]):
469     global plc
470     for i in args:
471         email = plc[i]['peer-admin-name']
472         try:
473             p=s[i].GetPersons([email])[0]
474             plc[i]['peer-admin-id']=p['person_id']
475         except:
476             person_id=s[i].AddPerson({'first_name':'Local', 
477                                       'last_name':'PeerPoint', 
478                                       'role_ids':[10],
479                                       'email':email,
480                                       'password':plc[i]['peer-admin-password']})
481             if person_id:
482                 print '%02d:== created peer admin account %d, %s - %s'%(
483                     i, person_id,plc[i]['peer-admin-name'],plc[i]['peer-admin-password'])
484             plc[i]['peer-admin-id']=person_id
485
486 def test00_admin_enable (args=[1,2]):
487     for i in args:
488         if s[i].AdmSetPersonEnabled(plc[i]['peer-admin-id'],True):
489             s[i].AddRoleToPerson('admin',plc[i]['peer-admin-id'])
490             print '%02d:== enabled+admin on account %d:%s'%(i,plc[i]['peer-admin-id'],plc[i]['peer-admin-name'])
491
492 ####################
493 def locate_key (filename):
494      " tries to locate a key file, either in . or in /etc/planetlab"
495      try:
496          return file("./"+filename).read()
497      except:
498          try:
499              return file("/etc/planetlab/"+filename).read()
500          except:
501              raise Exception,"Could not locate key %s"%filename
502              
503
504 def test00_peer (args=[1,2]):
505     global plc
506     for i in args:
507         peer=peer_index(i)
508         peername = plc_name(peer)
509         try:
510             p=s[i].GetPeers ( [peername])[0]
511         except:
512             try:
513                 keyringname=plc[i]['gpg-keyring']
514                 cacertname=plc[i]['api-cacert']
515                 print 'Trying to locate keys for peer on plc[%d]'%i,
516                 print 'in %s and %s'%(keyringname,cacertname)
517
518                 keyring=locate_key(keyringname)
519                 cacert=locate_key(cacertname)
520                 peer_id=s[i].AddPeer ( {'peername':peername,
521                                         'peer_url':plc[peer]['url'],
522                                         'key':keyring,
523                                         'cacert': cacert,
524                                         })
525                 print '%02d:Created peer %d'%(i,peer_id)
526             except Exception,e:
527                 print 'Could not create peer,',e
528     
529 # push various stuff across hosts through external ssh/scp
530 # this is broken, use peers-test.mk instead
531 #def test00_push_public_peer_material (args=[1,2]):
532 #    for i in args:
533 #       peer=peer_index(i)
534 #
535 #       ### the gpg keyring
536 #       # refresh
537 #       local_keyring="/etc/planetlab/gpg_keyring.pub"
538 #       command="ssh root@%s gpg --homedir=/etc/planetlab --export --armor > %s"\
539 #              %(plc[i]['hostname'],local_keyring)
540 #       retcod=os.system(command)
541 #       print '#',command,'->',retcod
542 #
543 #    for i in args:
544 #       peer=peer_index(i)
545 #       # push
546 #       src_url='root@%s:%s'%(plc[i]['hostname'],local_keyring)
547 #       dst_url='root@%s:%s'%(plc[peer]['hostname'], plc[i]['gpg-keyring'])
548 #       command = 'scp %s %s'%(src_url,dst_url)
549 #       retcod=os.system(command)
550 #       print '#',command,'->',retcod
551 #       
552 #    for i in args:
553 #       peer=peer_index(i)
554 #       # push cacert
555 #       local_cacert='/etc/planetlab/api_ca_ssl.crt'
556 #       src_url='root@%s:%s'%(plc[i]['hostname'],local_cacert)
557 #       dst_url='root@%s:%s'%(plc[peer]['hostname'], plc[i]['api-cacert'])
558 #       command = 'scp %s %s'%(src_url,dst_url)
559 #       retcod=os.system(command)
560 #       print '#',command,'->',retcod
561
562 # this one gets cached 
563 def get_peer_id (i):
564     try:
565         return plc[i]['peer_id']
566     except:
567         peername = plc_name (peer_index(i))
568         peer_id = s[i].GetPeers([peername])[0]['peer_id']
569         plc[i]['peer_id'] = peer_id
570         return peer_id
571
572 ##############################
573 def test00_refresh (message,args=[1,2]):
574     print '=== refresh',message
575     timer_show()
576     for i in args:
577         print '%02d:== Refreshing peer'%(i),
578         retcod=s[i].RefreshPeer(get_peer_id(i))
579         keys=retcod.keys()
580         keys.sort()
581         print "Result: {",
582         for key in keys:
583             if "time" not in key:
584                 print key,retcod[key],
585         print "}"
586         print "+++ ellapsed: {",
587         timers=retcod
588         keys=timers.keys()
589         keys.sort()
590         for key in keys:
591             print key,timers[key],
592         print "}"
593         timer_show()
594
595 ####################
596 def test01_site (args=[1,2]):
597     for ns in myrange(number_sites):
598         test01_site_n (ns,True,args)
599
600 def test01_del_site (args=[1,2]):
601     for ns in myrange(number_sites):
602         test01_site_n (ns,False,args)
603
604 def test01_site_n (ns,add_if_true,args=[1,2]):
605     for i in args:
606         login_base = site_login_base (i,ns)
607         try:
608             site_id = s[i].GetSites([login_base])[0]['site_id']
609             if not add_if_true:
610                 if s[i].DeleteSite(site_id):
611                     print "%02d:== deleted site_id %d"%(i,site_id)
612         except:
613             if add_if_true:
614                 sitename=site_name(i,ns)
615                 abbrev_name="abbr"+str(i)
616                 max_slices = number_slices
617                 site_id=s[i].AddSite ( {'name':plc_name(i),
618                                         'abbreviated_name': abbrev_name,
619                                         'login_base': login_base,
620                                         'is_public': True,
621                                         'url': 'http://%s.com/'%abbrev_name,
622                                         'max_slices':max_slices})
623                 ### max_slices does not seem taken into account at that stage
624                 if site_id:
625                     s[i].UpdateSite(site_id,{'max_slices':max_slices})
626                     print '%02d:== Created site %d with max_slices=%d'%(i,site_id,max_slices)
627
628 ####################
629 def test02_person (args=[1,2]):
630     for np in myrange(number_persons):
631         test02_person_n (np,True,args)
632
633 def test02_del_person (args=[1,2]):
634     for np in myrange(number_persons):
635         test02_person_n (np,False,args)
636
637 def test02_person_n (np,add_if_true,args=[1,2]):
638     test02_person_n_ks (np, myrange(number_keys_per_person),add_if_true,args)
639
640 def test02_person_n_ks (np,nks,add_if_true,args=[1,2]):
641     for i in args:
642         email = person_name(i,np)
643         try:
644             person_id=s[i].GetPersons([email])[0]['person_id']
645             if not add_if_true:
646                 if s[i].DeletePerson(person_id):
647                     print "%02d:== deleted person_id %d"%(i,person_id)
648         except:
649             if add_if_true:
650                 password = plc[i]['person-password']
651                 person_id=s[i].AddPerson({'first_name':'Your average', 
652                                                'last_name':'User%d'%np, 
653                                                'role_ids':[30],
654                                                'email':email,
655                                                'password': password })
656                 if person_id:
657                     print '%02d:== created user account %d, %s - %s'%(i, person_id,email,password)
658                     for nk in nks:
659                         key=key_name(i,np,nk)
660                         s[i].AddPersonKey(email,{'key_type':'ssh', 'key':key})
661                         print '%02d:== added key %s to person %s'%(i,key,email)
662
663 ####################
664 # retrieves node_id from hostname - checks for local nodes only
665 def get_local_node_id(i,nodename):
666     return s[i].GetNodes({'hostname':nodename,'peer_id':None})[0]['node_id']
667
668 # clean all local nodes - foreign nodes are not supposed to be cleaned up manually
669 def clean_all_nodes (args=[1,2]):
670     for i in args:
671         print '%02d:== Cleaning all nodes'%i
672         local_nodes = s[i].GetNodes({'peer_id':None})
673         if local_nodes:
674             for node in local_nodes:
675                 print '%02d:==== Cleaning node %d'%(i,node['node_id'])
676                 s[i].DeleteNode(node['node_id'])
677
678 def test03_node (args=[1,2]):
679     for nn in myrange(number_nodes):
680         test03_node_n (nn,args)
681
682 def test03_node_n (nn,args=[1,2]):
683     for i in args:
684         nodename = node_name(i,nn)
685         try:
686             get_local_node_id(i,nodename)
687         except:
688             login_base=site_login_base(i,map_on_site(nn))
689             n=s[i].AddNode(login_base,{'hostname': nodename})
690             if n:
691                 print '%02d:== Added node %d %s'%(i,n,node_name(i,nn))
692
693 def test02_delnode (args=[1,2]):
694     for nn in myrange(number_nodes):
695         test02_delnode_n (nn,args)
696
697 def test02_delnode_n (nn,args=[1,2]):
698     for i in args:
699         nodename = node_name(i,nn)
700         node_id = get_local_node_id (i,nodename)
701         retcod=s[i].DeleteNode(nodename)
702         if retcod:
703             print '%02d:== Deleted node %d, returns %s'%(i,node_id,retcod)
704
705 ####################
706 def clean_all_slices (args=[1,2]):
707     for i in args:
708         print '%02d:== Cleaning all slices'%i
709         for slice in s[i].GetSlices({'peer_id':None}):
710             slice_id = slice['slice_id']
711             if slice_id not in system_slices_ids:
712                 if s[i].DeleteSlice(slice_id):
713                     print '%02d:==== Cleaned slice %d'%(i,slice_id)
714
715 def test04_slice (args=[1,2]):
716     for n in myrange(number_slices):
717         test04_slice_n (n,args)
718
719 def test04_slice_n (ns,args=[1,2]):
720     for i in args:
721         peer=peer_index(i)
722         plcname=plc_name(i)
723         slicename=slice_name(i,ns)
724         max_nodes=number_nodes
725         try:
726             s[i].GetSlices([slicename])[0]
727         except:
728             slice_id=s[i].AddSlice ({'name':slicename,
729                                      'description':'slice %s on %s'%(slicename,plcname),
730                                      'url':'http://planet-lab.org/%s'%slicename,
731                                      'max_nodes':max_nodes,
732                                      'instanciation':'plc-instantiated',
733                                      })
734             if slice_id:
735                 print '%02d:== created slice %d - max nodes=%d'%(i,slice_id,max_nodes)
736                 actual_persons_per_slice = min (number_persons,number_persons_per_slice)
737                 person_indexes=[map_on_person (p+ns) for p in range(actual_persons_per_slice)]
738                 for np in person_indexes:
739                     email = person_name (i,np)
740                     retcod = s[i].AddPersonToSlice (email, slicename)
741                     print '%02d:== Attached person %s to slice %s'%(i,email,slicename)
742         
743
744 def test04_node_slice (is_local, add_if_true, args=[1,2]):
745     for ns in myrange(number_slices):
746         test04_node_slice_ns (ns,is_local, add_if_true, args)
747
748 def test04_node_slice_ns (ns,is_local, add_if_true, args=[1,2]):
749     actual_nodes_per_slice = min (number_nodes,number_nodes_per_slice)
750     node_indexes = [ map_on_node (n+ns) for n in range(actual_nodes_per_slice)]
751     test04_node_slice_nl_n (node_indexes,ns,is_local, add_if_true, args)
752
753 def test04_node_slice_nl_n (nnl,ns,is_local, add_if_true, args=[1,2]):
754     for i in args:
755         peer=peer_index(i)
756         sname = slice_name (i,ns)
757         
758         if is_local:
759             hostnames=[node_name(i,nn) for nn in nnl]
760             nodetype='local'
761         else:
762             hostnames=[node_name(peer,nn) for nn in nnl]
763             nodetype='foreign'
764         if add_if_true:
765             res=s[i].AddSliceToNodes (sname,hostnames)
766             message="added"
767         else:
768             res=s[i].DeleteSliceFromNodes (sname,hostnames)
769             message="deleted"
770         if res:
771             print '%02d:== %s in slice %s %s '%(i,message,sname,nodetype),
772             print hostnames
773
774 def test04_slice_add_lnode (args=[1,2]):
775     test04_node_slice (True,True,args)
776
777 def test04_slice_add_fnode (args=[1,2]):
778     test04_node_slice (False,True,args)
779
780 def test04_slice_del_lnode (args=[1,2]):
781     test04_node_slice (True,False,args)
782
783 def test04_slice_del_fnode (args=[1,2]):
784     test04_node_slice (False,False,args)
785
786 ####################
787 def test05_sat (args=[1,2]):
788     for i in args:
789         name = sat_name(i)
790         try:
791             sat_id=s[i].GetSliceAttributeTypes ([name])[0]
792         except:
793             description="custom sat on plc%d"%i
794             min_role_id=10
795             sat_id=s[i].AddSliceAttributeType ({ 'name':name,
796                                                  'description': description,
797                                                  'min_role_id' : min_role_id})
798             if sat_id:
799                 print '%02d:== created SliceAttributeType = %d'%(i,sat_id)
800
801 # for test, we create 4 slice_attributes
802 # on slice1 - sat=custom_made (see above) - all nodes
803 # on slice1 - sat=custom_made (see above) - node=n1
804 # on slice1 - sat='net_max' - all nodes
805 # on slice1 - sat='net_max' - node=n1
806
807 def test05_sa_atom (slice_name,sat_name,value,node,i):
808     sa_id=s[i].GetSliceAttributes({'name':sat_name,
809                                    'value':value})
810     if not sa_id:
811         if node:
812             sa_id=s[i].AddSliceAttribute(slice_name,
813                                          sat_name,
814                                          value,
815                                          node)
816         else:
817             print 'slice_name',slice_name,'sat_name',sat_name
818             sa_id=s[i].AddSliceAttribute(slice_name,
819                                          sat_name,
820                                          value)
821         if sa_id:
822             print '%02d:== created SliceAttribute = %d'%(i,sa_id),
823             print 'On slice',slice_name,'and node',node
824         
825 def test05_sa (args=[1,2]):
826     for i in args:
827         test05_sa_atom (slice_name(i,1),sat_name(i),'custom sat/all nodes',None,i)
828         test05_sa_atom (slice_name(i,1),sat_name(i),'custom sat/node1',node_name(i,1),i)
829         test05_sa_atom (slice_name(i,1),'vref','predefined sat/all nodes',None,i)
830         test05_sa_atom (slice_name(i,1),'vref','predefined sat/node1',node_name(i,1),i)
831         
832 ##############################
833 # readable dumps
834 ##############################
835 def p_site (s):
836     print s['site_id'],s['peer_id'],s['login_base'],s['name'],s['node_ids']
837
838 def p_key (k):
839     print  k['key_id'],k['peer_id'],k['key']
840     
841 def p_person (p):
842     print  p['person_id'],p['peer_id'],p['email'],'keys:',p['key_ids'],'sites:',p['site_ids']
843
844 def p_node(n):
845     print n['node_id'],n['peer_id'],n['hostname'],'sls=',n['slice_ids'],'site=',n['site_id']
846
847 def p_slice(s):
848     print 'name: %-12s'%s['name'],'id: %02d'%s['slice_id'],'peer:',s['peer_id'],'nodes=',s['node_ids'],'persons=',s['person_ids']
849     print '---','sa_ids=',s['slice_attribute_ids'],'creator: %03d'%s['creator_person_id']
850     print "--- 'expires':",s['expires']
851
852 def p_sat(sat):
853     print 'sat_id: %02d'%sat['attribute_type_id'], 'min_role_id:',sat['min_role_id'],
854     print 'name:', sat['name'],'<',sat['description'],'>'
855
856 def p_sa (sa):
857         print 'name: %-12s'%sa['name'], 
858         print 'sa_id: %02d'%sa['slice_attribute_id'],'sat_id: %02d'%sa['attribute_type_id'],
859         print 'sl=%02d'%sa['slice_id'],'v=',sa['value'],'n=',sa['node_id']
860
861 import pprint
862 pretty_printer=pprint.PrettyPrinter(5)
863
864 def p_sliver (margin,x):
865     print margin,'SLIVERS for : hostname',x['hostname']
866     print margin,'%d config files'%len(x['conf_files'])
867     for sv in x['slivers']:
868         p_sliver_slice(margin,sv,x['hostname'])
869
870 def p_sliver_slice(margin,sliver,hostname):
871     print margin,'SLIVER on hostname %s, s='%hostname,sliver['name']
872     print margin,'KEYS',
873     pretty_printer.pprint(sliver['keys'])
874     print margin,'ATTRIBUTES',
875     pretty_printer.pprint(sliver['attributes'])
876
877 def dump (args=[1,2]):
878     for i in args:
879         print '%02d:============================== DUMPING'%i
880         print '%02d: SITES'%i
881         [p_site(x) for x in s[i].GetSites()]
882         print '%02d: KEYS'%i
883         [p_key(x) for x in s[i].GetKeys()]
884         print '%02d: PERSONS'%i
885         [p_person(x) for x in s[i].GetPersons()]
886         print '%02d: NODES'%i
887         [p_node(x) for x in s[i].GetNodes()]
888         print '%02d: SLICES'%i
889         [p_slice(x) for x in s[i].GetSlices()]
890         print '%02d: Slice Attribute Types'%i
891         [p_sat(x) for x in s[i].GetSliceAttributeTypes()]
892         print '%02d: Slice Attributes'%i
893         [p_sa(x) for x in s[i].GetSliceAttributes()]
894         timer_show()
895         snodes=min(3,number_nodes)
896         print '%02d: SLIVERS for first %d nodes'%(i,snodes)
897         print 'WARNING - GetSlivers needs fix'
898 #        for id in myrange(snodes):
899 #            p_sliver('%02d:'%i,s[i].GetSlivers(id))
900
901         print '%02d:============================== END DUMP'%i
902     
903
904 ## for usage under the api
905 def pt ():
906     for x in GetSites():
907         p_site(x)
908         
909 def pk ():
910     for x in GetKeys():
911         print  (x['key_id'],x['peer_id'],x['key']) 
912
913 def pp ():
914     for x in GetPersons():
915         p_person(x)
916
917 def pn ():
918     for x in GetNodes():
919         p_node(x)
920
921 def ps ():
922     for x in GetSlices():
923         p_slice(x)
924
925 def psat():
926     for x in GetSliceAttributeTypes():
927         p_sat(x)
928         
929 def psa():
930     for x in GetSliceAttributes():
931         p_sa(x)
932         
933 def pv ():
934     for s in GetSlivers():
935         p_sliver('',s)
936
937 def all():
938     print 'SITES'
939     pt()
940     print 'KEYS'
941     pk()
942     print 'PERSONS'
943     pp()
944     print 'NODES'
945     pn()
946     print 'SLICES'
947     ps()
948     print 'SLICE ATTR TYPES'
949     psat()
950     print 'SLICE ATTRS'
951     psa()
952     print 'SLIVERS'
953     pv()
954
955
956 ####################
957 def test_all_init ():
958     message ("INIT")
959     test00_init (builtin_person=True)
960     test00_print ()
961     test00_admin_person ()
962     test00_admin_enable ()
963     test00_init (builtin_person=False)
964 # required before we can add peers
965 # use make -f peers-test.mk peers instead    
966 #    test00_push_public_peer_material()
967     test00_peer ()
968
969 def test_all_sites ():
970     test01_site ()
971     test00_refresh ('after site creation')
972
973 def test_all_persons ():
974     test02_del_person()
975     test00_refresh ('before persons&keys creation')
976     check_keys(0,0)
977     check_persons(system_persons,system_persons_cross)
978     message ("Creating persons&keys")
979     test02_person ()
980     if not fast_flag:
981         message ("1 extra del/add cycle for unique indexes")
982         test02_del_person([2])
983         test02_person([2])
984     check_keys(number_persons*number_keys_per_person,0)
985     check_persons(system_persons+number_persons,system_persons_cross)
986     test00_refresh ('after persons&keys creation')
987     check_keys(number_persons*number_keys_per_person,number_persons*number_keys_per_person)
988     check_persons(system_persons+number_persons,system_persons_cross+number_persons)
989
990 def test_all_nodes ():
991
992     message ("RESETTING NODES")
993     clean_all_nodes ()
994     test00_refresh ('cleaned nodes')
995     check_nodes(0,0)
996
997     # create one node on each site
998     message ("CREATING NODES")
999     test03_node ()
1000     check_nodes(number_nodes,0)
1001     test00_refresh ('after node creation')
1002     check_nodes(number_nodes,number_nodes)
1003     test02_delnode([2])
1004     if not fast_flag:
1005         message ("2 extra del/add cycles on plc2 for different indexes")
1006         test03_node ([2])
1007         test02_delnode([2])
1008         test03_node ([2])
1009         test02_delnode([2])
1010     check_nodes(0,number_nodes,[2])
1011     test00_refresh('after deletion on plc2')
1012     check_nodes(number_nodes,0,[1])
1013     check_nodes(0,number_nodes,[2])
1014     message ("ADD on plc2 for different indexes")
1015     test03_node ([2])
1016     check_nodes (number_nodes,0,[1])
1017     check_nodes (number_nodes,number_nodes,[2])
1018     test00_refresh('after re-creation on plc2')
1019     check_nodes (number_nodes,number_nodes,)
1020
1021 def test_all_addslices ():
1022
1023     # reset
1024     message ("RESETTING SLICES TEST")
1025     clean_all_nodes ()
1026     test03_node ()
1027     clean_all_slices ()
1028     test00_refresh ("After slices init")
1029
1030     # create slices on plc1
1031     message ("CREATING SLICES on plc1")
1032     test04_slice ([1])
1033
1034     check_slices (total_slices(),system_slices(),[1])
1035     check_slices (system_slices(),system_slices(),[2])
1036     test00_refresh ("after slice created on plc1")
1037     check_slices (total_slices(),system_slices(),[1])
1038     check_slices (system_slices(),total_slices(),[2])
1039     # no slice has any node yet
1040     check_local_slice_nodes(0,[1])
1041     check_foreign_slice_nodes(0,[2])
1042
1043     # insert local nodes in local slice on plc1
1044     message ("ADDING LOCAL NODES IN SLICES")
1045     test04_slice_add_lnode ([1])
1046     # of course the change is only local
1047     check_local_slice_nodes (number_nodes_per_slice,[1])
1048     check_foreign_slice_nodes(0,[2])
1049
1050     # refreshing
1051     test00_refresh ("After local nodes were added on plc1")
1052     check_local_slice_nodes (number_nodes_per_slice,[1])
1053     check_foreign_slice_nodes (number_nodes_per_slice,[2])
1054
1055     # now we add foreign nodes into local slice
1056     message ("ADDING FOREIGN NODES IN SLICES")
1057     test04_slice_add_fnode ([1])
1058     check_local_slice_nodes (2*number_nodes_per_slice,[1])
1059     check_foreign_slice_nodes (number_nodes_per_slice,[2])
1060
1061     # refreshing
1062     test00_refresh ("After foreign nodes were added in plc1")
1063     # remember that foreign slices only know about LOCAL nodes
1064     # so this does not do anything
1065     check_local_slice_nodes (2*number_nodes_per_slice,[1])
1066     check_foreign_slice_nodes (2*number_nodes_per_slice,[2])
1067
1068     check_slivers_1(total_slivers())
1069
1070 def test_all_delslices ():
1071
1072     message ("DELETING FOREIGN NODES FROM SLICES")
1073     test04_slice_del_fnode([1])
1074     check_local_slice_nodes (number_nodes_per_slice,[1])
1075     check_foreign_slice_nodes (2*number_nodes_per_slice,[2])
1076     # mmh?
1077     check_slivers_1(total_slivers(),[1])
1078
1079     test00_refresh ("After foreign nodes were removed on plc1")
1080     check_local_slice_nodes (number_nodes_per_slice,[1])
1081     check_foreign_slice_nodes (number_nodes_per_slice,[2])
1082     
1083     message ("DELETING LOCAL NODES FROM SLICES")
1084     test04_slice_del_lnode([1])
1085     check_local_slice_nodes (0,[1])
1086     check_foreign_slice_nodes (number_nodes_per_slice,[2])
1087
1088     test00_refresh ("After local nodes were removed on plc1")
1089     check_local_slice_nodes (0,[1])
1090     check_foreign_slice_nodes (0,[2])
1091
1092     message ("CHECKING SLICES CLEAN UP")
1093     clean_all_slices([1])
1094     check_slices (system_slices(),system_slices(),[1])
1095     check_slices (system_slices(),total_slices(),[2])
1096     test00_refresh ("After slices clenaup")
1097     check_slices(system_slices(),system_slices())
1098
1099 def test_all_slices ():
1100     test_all_addslices ()
1101     test_all_delslices ()
1102     
1103 def test_all_sats ():
1104     test05_sat ()
1105     test00_refresh("after SliceAttributeType creation")                   
1106
1107 def test_all ():
1108     test_all_init ()
1109     timer_show()
1110     test_all_sites ()
1111     timer_show()
1112     test_all_persons ()
1113     timer_show()
1114     test_all_nodes ()
1115     timer_show()
1116     test_all_slices ()
1117     timer_show()
1118     test_all_sats ()
1119     timer_show()
1120     dump()
1121     timer_show()
1122     message("END")
1123
1124 ### ad hoc test sequences
1125 # we just create objects here so we can dump the DB
1126 def populate ():
1127     timer_start()
1128     test_all_init()
1129     timer_show()
1130     test01_site()
1131     timer_show()
1132     test02_person()
1133     timer_show()
1134     test03_node()
1135     timer_show()
1136     test04_slice([1])
1137     timer_show()
1138     test04_slice_add_lnode([1])
1139     timer_show()
1140     test05_sat()
1141     timer_show()
1142     test05_sa([1])
1143     timer_show()
1144     message("END")
1145
1146 def populate_end():
1147     test00_init(builtin_person=False)
1148     test00_refresh ("Peer 1 for publishing foreign nodes from 2",[1])
1149     timer_show()
1150     test04_slice_add_fnode([1])
1151     timer_show()
1152     test00_refresh("populate: refresh all")
1153     timer_show()
1154     test00_refresh("empty refresh")
1155     dump()
1156     timer_show()
1157     message("END")
1158
1159 # temporary - scratch as needed
1160 def test_now ():
1161     test_all_init()
1162
1163 #    populate()
1164 #    test00_refresh('peer 1 gets plc2 nodes',[1])
1165 #    test04_slice_add_fnode([1])
1166 #    test00_refresh('final',[1])
1167 #    
1168 #    test_all_sites ()
1169 #    clean_all_nodes()
1170 #    clean_all_slices()
1171 #    populate()
1172
1173 #####
1174 def usage ():
1175     print "Usage: %s [-n] [-f]"%sys.argv[0]
1176     print " -n runs test_now instead of test_all"
1177     print " -p runs populate instead of test_all"
1178     print " -e runs populate_end of test_all"
1179     print " -m run in mini mode (1 instance of each class)"
1180     print " -b performs big run"
1181     print " -H performs huge run"
1182     print " -f n : increases normal sizes by <n>"
1183     print " -l n : tester runs locally for peer <n>, rather than through xmlrpc"
1184     
1185     sys.exit(1)
1186
1187 def main ():
1188     try:
1189         (o,a) = getopt.getopt(sys.argv[1:], "emnpbHf:l:")
1190     except:
1191         usage()
1192     func = test_all
1193     for (opt,val) in o:
1194         if opt=='-n':
1195             print 'Running test_now'
1196             func = test_now
1197         elif opt=='-p':
1198             print 'Running populate'
1199             func = populate
1200         elif opt=='-e':
1201             print 'Running populate_end'
1202             func = populate_end
1203         elif opt=='-m':
1204             mini()
1205         elif opt=='-b':
1206             big()
1207         elif opt=='-H':
1208             huge()
1209         elif opt=='-f':
1210             factor=int(val)
1211             apply_factor(factor)
1212         elif opt=='-l':
1213             global local_peer
1214             local_peer=int(val)
1215             if local_peer not in (1,2):
1216                 usage()
1217         else:
1218             usage()
1219     if a:
1220         usage()
1221     show_test()
1222     func()   
1223     timer_show()
1224     epilogue
1225
1226 if __name__ == '__main__':
1227     normal()
1228     main()
1229