for executable migration scripts
[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),'net_max','predefined sat/all nodes',None,i)
830         test05_sa_atom (slice_name(i,1),'net_max','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 s['slice_id'],s['peer_id'],s['name'],'nodes=',s['node_ids'],'persons=',s['person_ids']
849     print '---','sas=',s['slice_attribute_ids'],s['name'],'crp=',s['creator_person_id']
850     print "--- 'expires':",s['expires']
851
852 def p_sat(sat):
853     print sat['attribute_type_id'], sat['name'], sat['min_role_id'], sat['description']
854
855 def p_sa (sa):
856         print sa['slice_attribute_id'],sa['name'],'AT_id:',sa['attribute_type_id']
857         print '---','v=',sa['value'],'sl=',sa['slice_id'],'n=',sa['node_id']
858
859 import pprint
860 pretty_printer=pprint.PrettyPrinter(5)
861
862 def p_sliver (margin,x):
863     print margin,'SLIVERS for : hostname',x['hostname']
864     print margin,'%d config files'%len(x['conf_files'])
865     for sv in x['slivers']:
866         p_sliver_slice(margin,sv,x['hostname'])
867
868 def p_sliver_slice(margin,sliver,hostname):
869     print margin,'SLIVER on hostname %s, s='%hostname,sliver['name']
870     print margin,'KEYS',
871     pretty_printer.pprint(sliver['keys'])
872     print margin,'ATTRIBUTES',
873     pretty_printer.pprint(sliver['attributes'])
874
875 def dump (args=[1,2]):
876     for i in args:
877         print '%02d:============================== DUMPING'%i
878         print '%02d: SITES'%i
879         [p_site(x) for x in s[i].GetSites()]
880         print '%02d: KEYS'%i
881         [p_key(x) for x in s[i].GetKeys()]
882         print '%02d: PERSONS'%i
883         [p_person(x) for x in s[i].GetPersons()]
884         print '%02d: NODES'%i
885         [p_node(x) for x in s[i].GetNodes()]
886         print '%02d: SLICES'%i
887         [p_slice(x) for x in s[i].GetSlices()]
888         print '%02d: Slice Attribute Types'%i
889         [p_sat(x) for x in s[i].GetSliceAttributeTypes()]
890         print '%02d: Slice Attributes'%i
891         [p_sa(x) for x in s[i].GetSliceAttributes()]
892         timer_show()
893         snodes=min(3,number_nodes)
894         print '%02d: SLIVERS for first %d nodes'%(i,snodes)
895         print 'WARNING - GetSlivers needs fix'
896 #        for id in myrange(snodes):
897 #            p_sliver('%02d:'%i,s[i].GetSlivers(id))
898
899         print '%02d:============================== END DUMP'%i
900     
901
902 ## for usage under the api
903 def pt ():
904     for x in GetSites():
905         p_site(x)
906         
907 def pk ():
908     for x in GetKeys():
909         print  (x['key_id'],x['peer_id'],x['key']) 
910
911 def pp ():
912     for x in GetPersons():
913         p_person(x)
914
915 def pn ():
916     for x in GetNodes():
917         p_node(x)
918
919 def ps ():
920     for x in GetSlices():
921         p_slice(x)
922
923 def psat():
924     for x in GetSliceAttributeTypes():
925         p_sat(x)
926         
927 def psa():
928     for x in GetSliceAttributes():
929         p_sa(x)
930         
931 def pv ():
932     for s in GetSlivers():
933         p_sliver('',s)
934
935 def all():
936     print 'SITES'
937     pt()
938     print 'KEYS'
939     pk()
940     print 'PERSONS'
941     pp()
942     print 'NODES'
943     pn()
944     print 'SLICES'
945     ps()
946     print 'SLICE ATTR TYPES'
947     psat()
948     print 'SLICE ATTRS'
949     psa()
950     print 'SLIVERS'
951     pv()
952
953
954 ####################
955 def test_all_init ():
956     message ("INIT")
957     test00_init (builtin_person=True)
958     test00_print ()
959     test00_admin_person ()
960     test00_admin_enable ()
961     test00_init (builtin_person=False)
962 # required before we can add peers
963 # use make -f peers-test.mk peers instead    
964 #    test00_push_public_peer_material()
965     test00_peer ()
966
967 def test_all_sites ():
968     test01_site ()
969     test00_refresh ('after site creation')
970
971 def test_all_persons ():
972     test02_del_person()
973     test00_refresh ('before persons&keys creation')
974     check_keys(0,0)
975     check_persons(system_persons,system_persons_cross)
976     message ("Creating persons&keys")
977     test02_person ()
978     if not fast_flag:
979         message ("1 extra del/add cycle for unique indexes")
980         test02_del_person([2])
981         test02_person([2])
982     check_keys(number_persons*number_keys_per_person,0)
983     check_persons(system_persons+number_persons,system_persons_cross)
984     test00_refresh ('after persons&keys creation')
985     check_keys(number_persons*number_keys_per_person,number_persons*number_keys_per_person)
986     check_persons(system_persons+number_persons,system_persons_cross+number_persons)
987
988 def test_all_nodes ():
989
990     message ("RESETTING NODES")
991     clean_all_nodes ()
992     test00_refresh ('cleaned nodes')
993     check_nodes(0,0)
994
995     # create one node on each site
996     message ("CREATING NODES")
997     test03_node ()
998     check_nodes(number_nodes,0)
999     test00_refresh ('after node creation')
1000     check_nodes(number_nodes,number_nodes)
1001     test02_delnode([2])
1002     if not fast_flag:
1003         message ("2 extra del/add cycles on plc2 for different indexes")
1004         test03_node ([2])
1005         test02_delnode([2])
1006         test03_node ([2])
1007         test02_delnode([2])
1008     check_nodes(0,number_nodes,[2])
1009     test00_refresh('after deletion on plc2')
1010     check_nodes(number_nodes,0,[1])
1011     check_nodes(0,number_nodes,[2])
1012     message ("ADD on plc2 for different indexes")
1013     test03_node ([2])
1014     check_nodes (number_nodes,0,[1])
1015     check_nodes (number_nodes,number_nodes,[2])
1016     test00_refresh('after re-creation on plc2')
1017     check_nodes (number_nodes,number_nodes,)
1018
1019 def test_all_addslices ():
1020
1021     # reset
1022     message ("RESETTING SLICES TEST")
1023     clean_all_nodes ()
1024     test03_node ()
1025     clean_all_slices ()
1026     test00_refresh ("After slices init")
1027
1028     # create slices on plc1
1029     message ("CREATING SLICES on plc1")
1030     test04_slice ([1])
1031
1032     check_slices (total_slices(),system_slices(),[1])
1033     check_slices (system_slices(),system_slices(),[2])
1034     test00_refresh ("after slice created on plc1")
1035     check_slices (total_slices(),system_slices(),[1])
1036     check_slices (system_slices(),total_slices(),[2])
1037     # no slice has any node yet
1038     check_local_slice_nodes(0,[1])
1039     check_foreign_slice_nodes(0,[2])
1040
1041     # insert local nodes in local slice on plc1
1042     message ("ADDING LOCAL NODES IN SLICES")
1043     test04_slice_add_lnode ([1])
1044     # of course the change is only local
1045     check_local_slice_nodes (number_nodes_per_slice,[1])
1046     check_foreign_slice_nodes(0,[2])
1047
1048     # refreshing
1049     test00_refresh ("After local nodes were added on plc1")
1050     check_local_slice_nodes (number_nodes_per_slice,[1])
1051     check_foreign_slice_nodes (number_nodes_per_slice,[2])
1052
1053     # now we add foreign nodes into local slice
1054     message ("ADDING FOREIGN NODES IN SLICES")
1055     test04_slice_add_fnode ([1])
1056     check_local_slice_nodes (2*number_nodes_per_slice,[1])
1057     check_foreign_slice_nodes (number_nodes_per_slice,[2])
1058
1059     # refreshing
1060     test00_refresh ("After foreign nodes were added in plc1")
1061     # remember that foreign slices only know about LOCAL nodes
1062     # so this does not do anything
1063     check_local_slice_nodes (2*number_nodes_per_slice,[1])
1064     check_foreign_slice_nodes (2*number_nodes_per_slice,[2])
1065
1066     check_slivers_1(total_slivers())
1067
1068 def test_all_delslices ():
1069
1070     message ("DELETING FOREIGN NODES FROM SLICES")
1071     test04_slice_del_fnode([1])
1072     check_local_slice_nodes (number_nodes_per_slice,[1])
1073     check_foreign_slice_nodes (2*number_nodes_per_slice,[2])
1074     # mmh?
1075     check_slivers_1(total_slivers(),[1])
1076
1077     test00_refresh ("After foreign nodes were removed on plc1")
1078     check_local_slice_nodes (number_nodes_per_slice,[1])
1079     check_foreign_slice_nodes (number_nodes_per_slice,[2])
1080     
1081     message ("DELETING LOCAL NODES FROM SLICES")
1082     test04_slice_del_lnode([1])
1083     check_local_slice_nodes (0,[1])
1084     check_foreign_slice_nodes (number_nodes_per_slice,[2])
1085
1086     test00_refresh ("After local nodes were removed on plc1")
1087     check_local_slice_nodes (0,[1])
1088     check_foreign_slice_nodes (0,[2])
1089
1090     message ("CHECKING SLICES CLEAN UP")
1091     clean_all_slices([1])
1092     check_slices (system_slices(),system_slices(),[1])
1093     check_slices (system_slices(),total_slices(),[2])
1094     test00_refresh ("After slices clenaup")
1095     check_slices(system_slices(),system_slices())
1096
1097 def test_all_slices ():
1098     test_all_addslices ()
1099     test_all_delslices ()
1100     
1101 def test_all_sats ():
1102     test05_sat ()
1103     test00_refresh("after SliceAttributeType creation")                   
1104
1105 def test_all ():
1106     test_all_init ()
1107     timer_show()
1108     test_all_sites ()
1109     timer_show()
1110     test_all_persons ()
1111     timer_show()
1112     test_all_nodes ()
1113     timer_show()
1114     test_all_slices ()
1115     timer_show()
1116     test_all_sats ()
1117     timer_show()
1118     dump()
1119     timer_show()
1120     message("END")
1121
1122 ### ad hoc test sequences
1123 # we just create objects here so we can dump the DB
1124 def populate ():
1125     timer_start()
1126     test_all_init()
1127     timer_show()
1128     test01_site()
1129     timer_show()
1130     test02_person()
1131     timer_show()
1132     test03_node()
1133     timer_show()
1134     test04_slice([1])
1135     timer_show()
1136     test04_slice_add_lnode([1])
1137     timer_show()
1138     test05_sat()
1139     timer_show()
1140     test05_sa([1])
1141     timer_show()
1142     message("END")
1143
1144 def populate_end():
1145     test00_init(builtin_person=False)
1146     test00_refresh ("Peer 1 for publishing foreign nodes from 2",[1])
1147     timer_show()
1148     test04_slice_add_fnode([1])
1149     timer_show()
1150     test00_refresh("populate: refresh all")
1151     timer_show()
1152     test00_refresh("empty refresh")
1153     dump()
1154     timer_show()
1155     message("END")
1156
1157 # temporary - scratch as needed
1158 def test_now ():
1159     test_all_init()
1160
1161 #    populate()
1162 #    test00_refresh('peer 1 gets plc2 nodes',[1])
1163 #    test04_slice_add_fnode([1])
1164 #    test00_refresh('final',[1])
1165 #    
1166 #    test_all_sites ()
1167 #    clean_all_nodes()
1168 #    clean_all_slices()
1169 #    populate()
1170
1171 #####
1172 def usage ():
1173     print "Usage: %s [-n] [-f]"%sys.argv[0]
1174     print " -n runs test_now instead of test_all"
1175     print " -p runs populate instead of test_all"
1176     print " -e runs populate_end of test_all"
1177     print " -m run in mini mode (1 instance of each class)"
1178     print " -b performs big run"
1179     print " -H performs huge run"
1180     print " -f n : increases normal sizes by <n>"
1181     print " -l n : tester runs locally for peer <n>, rather than through xmlrpc"
1182     
1183     sys.exit(1)
1184
1185 def main ():
1186     try:
1187         (o,a) = getopt.getopt(sys.argv[1:], "emnpbHf:l:")
1188     except:
1189         usage()
1190     func = test_all
1191     for (opt,val) in o:
1192         if opt=='-n':
1193             print 'Running test_now'
1194             func = test_now
1195         elif opt=='-p':
1196             print 'Running populate'
1197             func = populate
1198         elif opt=='-e':
1199             print 'Running populate_end'
1200             func = populate_end
1201         elif opt=='-m':
1202             mini()
1203         elif opt=='-b':
1204             big()
1205         elif opt=='-H':
1206             huge()
1207         elif opt=='-f':
1208             factor=int(val)
1209             apply_factor(factor)
1210         elif opt=='-l':
1211             global local_peer
1212             local_peer=int(val)
1213             if local_peer not in (1,2):
1214                 usage()
1215         else:
1216             usage()
1217     if a:
1218         usage()
1219     show_test()
1220     func()   
1221     timer_show()
1222     epilogue
1223
1224 if __name__ == '__main__':
1225     normal()
1226     main()
1227