3 # Test script utility class
5 # Mark Huang <mlhuang@cs.princeton.edu>
6 # Copyright (C) 2006 The Trustees of Princeton University
9 # NOTE on porting to python3
11 # this file gets fed to plcsh on the tested myplc, so
12 # it needs to remain python2 for now
15 from pprint import pprint
16 from string import letters, digits, punctuation, whitespace
17 from traceback import print_exc
18 from optparse import OptionParser
25 from PLC.Shell import Shell
27 from random import Random
30 # note about namelengths
31 # original version uses full lengths for all fields for testing overflows and things
32 # however for a realistic test, involving a web UI, this is not appropriate, so we
33 # use smaller identifiers
35 def randfloat(min = 0.0, max = 1.0):
36 return float(min) + (random.random() * (float(max) - float(min)))
38 def randint(min = 0, max = 1):
39 return int(randfloat(min, max + 1))
41 # See "2.2 Characters" in the XML specification:
43 # #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
45 # [#x7F-#x84], [#x86-#x9F], [#xFDD0-#xFDDF]
48 ascii_xml_chars = map(unichr, [0x9, 0xA])
49 # xmlrpclib uses xml.parsers.expat, which always converts either '\r'
50 # (#xD) or '\n' (#xA) to '\n'. So avoid using '\r', too, if this is
52 if xmlrpclib.loads(xmlrpclib.dumps(('\r',)))[0][0] == '\r':
53 ascii_xml_chars.append('\r')
54 ascii_xml_chars += map(unichr, xrange(0x20, 0x7F - 1))
55 low_xml_chars = list(ascii_xml_chars)
56 low_xml_chars += map(unichr, xrange(0x84 + 1, 0x86 - 1))
57 low_xml_chars += map(unichr, xrange(0x9F + 1, 0xFF))
58 valid_xml_chars = list(low_xml_chars)
59 valid_xml_chars += map(unichr, xrange(0xFF + 1, 0xD7FF))
60 valid_xml_chars += map(unichr, xrange(0xE000, 0xFDD0 - 1))
61 valid_xml_chars += map(unichr, xrange(0xFDDF + 1, 0xFFFD))
63 def randstr(length, pool = valid_xml_chars, encoding = "utf-8"):
64 sample = random.sample(pool, min(length, len(pool)))
67 bytes = len(s.encode(encoding))
71 sample += random.sample(pool, min(length - bytes, len(pool)))
72 random.shuffle(sample)
77 def randhostname(namelengths):
78 # 1. Each part begins and ends with a letter or number.
79 # 2. Each part except the last can contain letters, numbers, or hyphens.
80 # 3. Each part is between 1 and 64 characters, including the trailing dot.
81 # 4. At least two parts.
82 # 5. Last part can only contain between 2 and 6 letters.
83 hostname = 'a' + randstr(namelengths['hostname1'], letters + digits + '-') + '1.' + \
84 'b' + randstr(namelengths['hostname1'], letters + digits + '-') + '2.' + \
85 'c' + randstr(namelengths['hostname2'], letters)
86 return hostname.lower()
90 for i in range(randint(1, 10)):
91 parts.append(randstr(randint(1, 30), ascii_xml_chars))
92 return u'/'.join(parts)[0:length]
94 def randemail(namelengths):
95 return (randstr(namelengths['email'], letters + digits) + "@" + randhostname(namelengths)).lower()
97 def randkey(namelengths,bits = 2048):
98 ssh_key_types = ["ssh-dss", "ssh-rsa"]
99 key_type = random.sample(ssh_key_types, 1)[0]
100 return ' '.join([key_type,
101 base64.b64encode(''.join(randstr(bits / 8).encode("utf-8"))),
102 randemail(namelengths)])
106 'peername': randstr(24,letters + ' ' + digits),
107 'peer_url': "https://" + randhostname ({'hostname1':8,'hostname2':3}) + ":443/PLCAPI/",
108 'key' : randstr(1024,letters+digits),
109 'cacert' : randstr(1024,letters+digits),
110 'shortname' : randstr(1,letters) + 'LAB',
111 'hrn_root' : 'planetlab.' + randstr (3,letters),
114 def random_site(namelengths):
115 sitename=randstr(namelengths['sitename'],namelengths['sitename_contents'])
116 abbreviated_name=randstr(namelengths['abbreviated_name'],namelengths['abbreviated_name_contents'])
118 print 'nl[a] in random_site',namelengths['abbreviated_name'],'actual',len(abbreviated_name)
121 'abbreviated_name': abbreviated_name,
122 'login_base': randstr(namelengths['login_base'], letters).lower(),
123 'latitude': int(randfloat(-90.0, 90.0) * 1000) / 1000.0,
124 'longitude': int(randfloat(-180.0, 180.0) * 1000) / 1000.0,
127 def random_address_type():
130 'description': randstr(254),
133 def random_address():
135 'line1': randstr(254),
136 'line2': randstr(254),
137 'line3': randstr(254),
138 'city': randstr(254),
139 'state': randstr(254),
140 'postalcode': randstr(64),
141 'country': randstr(128),
144 def random_person(namelengths):
146 'first_name': randstr(namelengths['first_name']),
147 'last_name': randstr(namelengths['last_name']),
148 'email': randemail(namelengths),
150 # Accounts are disabled by default
152 'password': randstr(254),
155 def random_key(key_types,namelengths):
157 'key_type': random.sample(key_types, 1)[0],
158 'key': randkey(namelengths)
161 def random_tag_type (role_ids):
162 return {'tagname': randstr(12,letters+digits),
163 'category':randstr(4,letters+digits)+'/'+randstr(6,letters+digits),
164 'description' : randstr(128,letters+digits+whitespace+punctuation),
167 def random_nodegroup():
168 return {'groupname' : randstr(30, letters+digits+whitespace) }
170 def random_roles(role_ids):
171 nb_roles=len(role_ids)
172 return random.sample(role_ids,random.choice(range(1,nb_roles+1)))
175 def random_node(node_types,boot_states,namelengths):
177 'hostname': randhostname(namelengths),
178 'node_type': random.sample(node_types,1)[0],
179 'boot_state': random.sample(boot_states, 1)[0],
180 'model': randstr(namelengths['model']),
181 'version': randstr(64),
182 # for testing node tags
186 def random_interface(method, type,namelengths):
190 'bwlimit': randint(500000, 10000000),
194 ip = randint(0, 0xffffffff)
195 netmask = (0xffffffff << randint(2, 31)) & 0xffffffff
196 network = ip & netmask
197 broadcast = ((ip & netmask) | ~netmask) & 0xffffffff
198 gateway = randint(network + 1, broadcast - 1)
199 dns1 = randint(0, 0xffffffff)
201 for field in 'ip', 'netmask', 'network', 'broadcast', 'gateway', 'dns1':
202 interface_fields[field] = socket.inet_ntoa(struct.pack('>L', locals()[field]))
204 interface_fields['hostname']=randhostname(namelengths);
206 return interface_fields
211 def random_pcu(namelengths):
213 'hostname': randhostname(namelengths),
214 'ip': socket.inet_ntoa(struct.pack('>L', randint(0, 0xffffffff))),
215 'protocol': randstr(16),
216 'username': randstr(254),
217 'password': randstr(254),
218 'notes': randstr(254),
219 'model': randstr(32),
222 def random_conf_file():
224 'enabled': bool(randint()),
225 'source': randpath(255),
226 'dest': randpath(255),
227 'file_permissions': "%#o" % randint(0, 512),
228 'file_owner': randstr(32, letters + '_' + digits),
229 'file_group': randstr(32, letters + '_' + digits),
230 'preinstall_cmd': randpath(100),
231 'postinstall_cmd': randpath(100),
232 'error_cmd': randpath(100),
233 'ignore_cmd_errors': bool(randint()),
234 'always_update': bool(randint()),
237 def random_slice(login_base,namelengths):
239 'name': login_base + "_" + randstr(11, letters).lower(),
240 'url': "http://" + randhostname(namelengths) + "/",
241 'description': randstr(2048),
248 'addresses_per_site': 1,
249 'persons_per_site': 1,
250 'keys_per_person': 1,
254 'interfaces_per_node': 1,
258 'slices_per_site': 1,
259 'attributes_per_slice': 1,
265 'addresses_per_site': 2,
266 'persons_per_site': 4,
267 'keys_per_person': 2,
271 'interfaces_per_node': 1,
275 'slices_per_site': 4,
276 'attributes_per_slice': 2,
282 'addresses_per_site': 2,
283 'persons_per_site': 5,
284 'keys_per_person': 2,
288 'interfaces_per_node': 2,
292 'slices_per_site': 10,
293 'attributes_per_slice': 4,
299 'addresses_per_site': 2,
300 'persons_per_site': 5,
301 'keys_per_person': 2,
305 'interfaces_per_node': 2,
309 'slices_per_site': 10,
310 'attributes_per_slice': 4,
313 namelengths_default = {
318 'sitename_contents':letters+digits,
319 'abbreviated_name':50,
320 'abbreviated_name_contents':letters+digits+whitespace+punctuation,
327 namelengths_short = {
332 'sitename_contents':letters+digits,
333 'abbreviated_name':24,
334 'abbreviated_name_contents':letters+digits+whitespace+punctuation,
341 def __init__(self, api, check, verbose, preserve, federating):
344 self.verbose = verbose
345 self.preserve = preserve
346 self.federating = federating
349 self.address_type_ids = []
350 self.address_ids = []
353 self.slice_type_ids = []
354 self.nodegroup_type_ids = []
355 self.ilink_type_ids = []
356 self.nodegroup_ids = []
358 self.interface_ids = []
361 self.conf_file_ids = []
363 self.slice_tag_ids = []
365 def Cardinals (self):
366 return [len(x) for x in (
367 self.api.GetNodes({},['node_id']),
368 self.api.GetSites({},['site_id']),
369 self.api.GetPersons({},['person_id']),
370 self.api.GetSlices({},['slice_id']),
373 def Run(self, **kwds):
375 Run a complete database and API consistency test. Populates
376 the database with a set of random entities, updates them, then
377 deletes them. Examples:
379 test.Run() # Defaults
380 test.Run(**Test.sizes_default) # Defaults
381 test.Run(**Test.sizes_tiny) # Tiny set
382 test.Run(sites = 123, slices_per_site = 4) # Defaults with overrides
385 cardinals_before=self.Cardinals()
386 print 'Cardinals before test (n,s,p,sl)',cardinals_before
389 # if federating : we're done
391 if self.federating or self.preserve:
392 print 'Preserving - update & delete skipped'
397 cardinals_after=self.Cardinals()
398 print 'Cardinals after test (n,s,p,sl)',cardinals_after
400 if cardinals_before != cardinals_after:
401 raise Exception, 'cardinals before and after differ - check deletion mechanisms'
403 def Add(self, **kwds):
405 Populate the database with a set of random entities. Examples:
410 sizes = self.sizes_default.copy()
413 if not self.federating:
414 self.AddSites(sizes['sites'])
415 self.AddAddressTypes(sizes['address_types'])
416 self.AddAddresses(sizes['addresses_per_site'])
417 self.AddPersons(sizes['persons_per_site'])
418 self.AddKeys(sizes['keys_per_person'])
419 self.AddTagTypes(sizes['slice_tags'],sizes['nodegroups'],sizes['ilinks'])
420 self.AddNodeGroups(sizes['nodegroups'])
421 self.AddNodes(sizes['nodes_per_site'])
422 self.AddInterfaces(sizes['interfaces_per_node'])
423 self.AddIlinks (sizes['ilinks'])
424 self.AddPCUs(sizes['pcus_per_site'])
425 self.AddConfFiles(sizes['conf_files'])
426 self.AddSlices(sizes['slices_per_site'])
427 self.AddSliceTags(sizes['attributes_per_slice'])
431 self.AddSites(sizes['sites'])
432 self.AddPersons(sizes['persons_per_site'])
433 self.AddKeys(sizes['keys_per_person'])
434 self.AddNodes(sizes['nodes_per_site'])
435 self.AddSlices(sizes['slices_per_site'])
436 # create peer and add newly created entities
442 self.UpdateAddressTypes()
443 self.UpdateAddresses()
446 self.UpdateTagTypes()
447 self.UpdateNodeGroups()
449 self.UpdateInterfaces()
452 self.UpdateConfFiles()
454 self.UpdateSliceTags()
457 self.DeleteSliceTags()
460 self.DeleteConfFiles()
463 self.DeleteInterfaces()
466 self.DeleteNodeGroups()
467 self.DeleteTagTypes()
468 self.DeleteAddresses()
469 self.DeleteAddressTypes()
472 # record current (old) objects
473 def RecordStatus (self):
474 self.old_site_ids = [ s['site_id'] for s in self.api.GetSites({},['site_id']) ]
475 self.old_person_ids = [ s['person_id'] for s in self.api.GetPersons({},['person_id']) ]
476 self.old_key_ids = [ s['key_id'] for s in self.api.GetKeys({},['key_id']) ]
477 self.old_node_ids = [ s['node_id'] for s in self.api.GetNodes({},['node_id']) ]
478 self.old_slice_ids = [ s['slice_id'] for s in self.api.GetSlices({},['slice_id']) ]
481 peer_id=self.api.AddPeer (random_peer())
482 peer = GetPeers([peer_id])[0]
484 print "Added peer",peer_id
486 # add new sites (the ones not in self.site_ids) in the peer
488 for site in self.api.GetSites ({'~site_id':self.old_site_ids}):
489 peer.add_site(site,site['site_id'])
490 for person in self.api.GetPersons ({'~person_id':self.old_person_ids}):
491 peer.add_person(person,person['person_id'])
492 for key in self.api.GetKeys ({'~key_id':self.old_key_ids}):
493 peer.add_key(key,key['key_id'])
494 for node in self.api.GetNodes ({'~node_id':self.old_node_ids}):
495 peer.add_node(node,node['node_id'])
496 for slice in self.api.GetSlices ({'~slice_id':self.old_slice_ids}):
497 peer.add_slice(slice,slice['slice_id'])
499 def AddSites(self, n = 10):
501 Add a number of random sites.
506 site_fields = random_site(self.namelengths)
507 site_id = self.api.AddSite(site_fields)
509 # Should return a unique site_id
510 assert site_id not in self.site_ids
511 self.site_ids.append(site_id)
513 # Enable slice creation
514 site_fields['max_slices'] = randint(1, 10)
515 self.api.UpdateSite(site_id, site_fields)
519 site = self.api.GetSites([site_id])[0]
520 for field in site_fields:
521 assert site[field] == site_fields[field]
524 print "Added site", site_id
526 def UpdateSites(self):
528 Make random changes to any sites we may have added.
531 for site_id in self.site_ids:
533 site_fields = random_site(self.namelengths)
534 # Do not change login_base
535 if 'login_base' in site_fields:
536 del site_fields['login_base']
537 self.api.UpdateSite(site_id, site_fields)
541 site = self.api.GetSites([site_id])[0]
542 for field in site_fields:
543 assert site[field] == site_fields[field]
546 print "Updated site", site_id
548 def DeleteSites(self):
550 Delete any random sites we may have added.
553 for site_id in self.site_ids:
554 self.api.DeleteSite(site_id)
557 assert not self.api.GetSites([site_id])
560 print "Deleted site", site_id
563 assert not self.api.GetSites(self.site_ids)
567 def AddAddressTypes(self, n = 2):
569 Add a number of random address types.
573 address_type_fields = random_address_type()
574 address_type_id = self.api.AddAddressType(address_type_fields)
576 # Should return a unique address_type_id
577 assert address_type_id not in self.address_type_ids
578 self.address_type_ids.append(address_type_id)
582 address_type = self.api.GetAddressTypes([address_type_id])[0]
583 for field in address_type_fields:
584 assert address_type[field] == address_type_fields[field]
587 print "Added address type", address_type_id
589 def UpdateAddressTypes(self):
591 Make random changes to any address types we may have added.
594 for address_type_id in self.address_type_ids:
595 # Update address_type
596 address_type_fields = random_address_type()
597 self.api.UpdateAddressType(address_type_id, address_type_fields)
601 address_type = self.api.GetAddressTypes([address_type_id])[0]
602 for field in address_type_fields:
603 assert address_type[field] == address_type_fields[field]
606 print "Updated address_type", address_type_id
608 def DeleteAddressTypes(self):
610 Delete any random address types we may have added.
613 for address_type_id in self.address_type_ids:
614 self.api.DeleteAddressType(address_type_id)
617 assert not self.api.GetAddressTypes([address_type_id])
620 print "Deleted address type", address_type_id
623 assert not self.api.GetAddressTypes(self.address_type_ids)
625 self.address_type_ids = []
627 def AddAddresses(self, per_site = 2):
629 Add a number of random addresses to each site.
632 for site_id in self.site_ids:
633 for i in range(per_site):
634 address_fields = random_address()
635 address_id = self.api.AddSiteAddress(site_id, address_fields)
637 # Should return a unique address_id
638 assert address_id not in self.address_ids
639 self.address_ids.append(address_id)
641 # Add random address type
642 if self.address_type_ids:
643 for address_type_id in random.sample(self.address_type_ids, 1):
644 self.api.AddAddressTypeToAddress(address_type_id, address_id)
648 address = self.api.GetAddresses([address_id])[0]
649 for field in address_fields:
650 assert address[field] == address_fields[field]
653 print "Added address", address_id, "to site", site_id
655 def UpdateAddresses(self):
657 Make random changes to any addresses we may have added.
660 for address_id in self.address_ids:
662 address_fields = random_address()
663 self.api.UpdateAddress(address_id, address_fields)
667 address = self.api.GetAddresses([address_id])[0]
668 for field in address_fields:
669 assert address[field] == address_fields[field]
672 print "Updated address", address_id
674 def DeleteAddresses(self):
676 Delete any random addresses we may have added.
679 for address_id in self.address_ids:
680 # Remove address types
681 address = self.api.GetAddresses([address_id])[0]
682 for address_type_id in address['address_type_ids']:
683 self.api.DeleteAddressTypeFromAddress(address_type_id, address_id)
686 address = self.api.GetAddresses([address_id])[0]
687 assert not address['address_type_ids']
689 self.api.DeleteAddress(address_id)
692 assert not self.api.GetAddresses([address_id])
695 print "Deleted address", address_id
698 assert not self.api.GetAddresses(self.address_ids)
700 self.address_ids = []
702 def AddPersons(self, per_site = 10):
704 Add a number of random users to each site.
707 for site_id in self.site_ids:
708 for i in range(per_site):
710 person_fields = random_person(self.namelengths)
711 person_id = self.api.AddPerson(person_fields)
713 # Should return a unique person_id
714 assert person_id not in self.person_ids
715 self.person_ids.append(person_id)
719 person = self.api.GetPersons([person_id])[0]
720 for field in person_fields:
721 if field != 'password':
722 assert person[field] == person_fields[field]
724 auth = {'AuthMethod': "password",
725 'Username': person_fields['email'],
726 'AuthString': person_fields['password']}
729 # Check that user is disabled
731 assert not self.api.AuthCheck(auth)
735 # Add random set of roles
736 role_ids = random.sample([20, 30, 40], randint(1, 3))
737 for role_id in role_ids:
738 self.api.AddRoleToPerson(role_id, person_id)
741 person = self.api.GetPersons([person_id])[0]
742 assert set(role_ids) == set(person['role_ids'])
745 self.api.UpdatePerson(person_id, {'enabled': True})
748 # Check that user is enabled
749 assert self.api.AuthCheck(auth)
751 # Associate user with site
752 self.api.AddPersonToSite(person_id, site_id)
753 self.api.SetPersonPrimarySite(person_id, site_id)
756 person = self.api.GetPersons([person_id])[0]
757 assert person['site_ids'][0] == site_id
760 print "Added user", person_id, "to site", site_id
762 def UpdatePersons(self):
764 Make random changes to any users we may have added.
767 for person_id in self.person_ids:
769 person_fields = random_person(self.namelengths)
771 person_fields['enabled'] = True
772 self.api.UpdatePerson(person_id, person_fields)
776 person = self.api.GetPersons([person_id])[0]
777 for field in person_fields:
778 if field != 'password':
779 assert person[field] == person_fields[field]
782 print "Updated person", person_id
784 person = self.api.GetPersons([person_id])[0]
786 # Associate user with a random set of sites
787 site_ids = random.sample(self.site_ids, randint(0, len(self.site_ids)))
788 for site_id in (set(site_ids) - set(person['site_ids'])):
789 self.api.AddPersonToSite(person_id, site_id)
790 for site_id in (set(person['site_ids']) - set(site_ids)):
791 self.api.DeletePersonFromSite(person_id, site_id)
794 self.api.SetPersonPrimarySite(person_id, site_ids[0])
797 person = self.api.GetPersons([person_id])[0]
798 assert set(site_ids) == set(person['site_ids'])
801 print "Updated person", person_id, "to sites", site_ids
803 def DeletePersons(self):
805 Delete any random users we may have added.
808 for person_id in self.person_ids:
810 person = self.api.GetPersons([person_id])[0]
811 for site_id in person['site_ids']:
812 self.api.DeletePersonFromSite(person_id, site_id)
815 person = self.api.GetPersons([person_id])[0]
816 assert not person['site_ids']
819 for role_id in person['role_ids']:
820 self.api.DeleteRoleFromPerson(role_id, person_id)
823 person = self.api.GetPersons([person_id])[0]
824 assert not person['role_ids']
827 self.api.UpdatePerson(person_id, {'enabled': False})
830 person = self.api.GetPersons([person_id])[0]
831 assert not person['enabled']
834 self.api.DeletePerson(person_id)
837 assert not self.api.GetPersons([person_id])
840 print "Deleted user", person_id
843 assert not self.api.GetPersons(self.person_ids)
847 def AddKeys(self, per_person = 2):
849 Add a number of random keys to each user.
852 key_types = self.api.GetKeyTypes()
854 raise Exception, "No key types"
856 for person_id in self.person_ids:
857 for i in range(per_person):
859 key_fields = random_key(key_types,self.namelengths)
860 key_id = self.api.AddPersonKey(person_id, key_fields)
862 # Should return a unique key_id
863 assert key_id not in self.key_ids
864 self.key_ids.append(key_id)
868 key = self.api.GetKeys([key_id])[0]
869 for field in key_fields:
870 assert key[field] == key_fields[field]
872 # Add and immediately blacklist a key
873 key_fields = random_key(key_types,self.namelengths)
874 key_id = self.api.AddPersonKey(person_id, key_fields)
876 self.api.BlacklistKey(key_id)
878 # Is effectively deleted
879 assert not self.api.GetKeys([key_id])
881 # Cannot be added again
883 key_id = self.api.AddPersonKey(person_id, key_fields)
889 print "Added key", key_id, "to user", person_id
891 def UpdateKeys(self):
893 Make random changes to any keys we may have added.
896 key_types = self.api.GetKeyTypes()
898 raise Exception, "No key types"
900 for key_id in self.key_ids:
902 key_fields = random_key(key_types,self.namelengths)
903 self.api.UpdateKey(key_id, key_fields)
907 key = self.api.GetKeys([key_id])[0]
908 for field in key_fields:
909 assert key[field] == key_fields[field]
912 print "Updated key", key_id
914 def DeleteKeys(self):
916 Delete any random keys we may have added.
919 for key_id in self.key_ids:
920 self.api.DeleteKey(key_id)
923 assert not self.api.GetKeys([key_id])
926 print "Deleted key", key_id
929 assert not self.api.GetKeys(self.key_ids)
933 def AddNodeGroups(self, n = 10):
935 Add a number of random node groups.
940 tag_type_id = self.nodegroup_type_ids[i]
941 tagname=self.api.GetTagTypes([tag_type_id])[0]['tagname']
944 groupname = random_nodegroup() ['groupname']
946 nodegroup_id = self.api.AddNodeGroup(groupname, tagname, value)
948 # Should return a unique nodegroup_id
949 assert nodegroup_id not in self.nodegroup_ids
950 self.nodegroup_ids.append(nodegroup_id)
954 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
955 assert nodegroup['groupname'] == groupname
956 assert nodegroup['tagname'] == tagname
957 assert nodegroup['value'] == value
960 print "Added node group", nodegroup_id
962 def UpdateNodeGroups(self):
964 Make random changes to any node groups we may have added.
967 for nodegroup_id in self.nodegroup_ids:
969 groupname = random_nodegroup()['groupname']
970 # cannot change tagname
971 nodegroup_fields = { 'groupname':groupname }
972 self.api.UpdateNodeGroup(nodegroup_id, nodegroup_fields)
976 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
977 for field in nodegroup_fields:
978 assert nodegroup[field] == nodegroup_fields[field]
981 print "Updated node group", nodegroup_id
983 def DeleteNodeGroups(self):
985 Delete any random node groups we may have added.
988 for nodegroup_id in self.nodegroup_ids:
989 self.api.DeleteNodeGroup(nodegroup_id)
992 assert not self.api.GetNodeGroups([nodegroup_id])
995 print "Deleted node group", nodegroup_id
998 assert not self.api.GetNodeGroups(self.nodegroup_ids)
1000 self.nodegroup_ids = []
1002 def AddNodes(self, per_site = 2):
1004 Add a number of random nodes to each site. Each node will also
1005 be added to a random node group if AddNodeGroups() was
1009 node_types = self.api.GetNodeTypes()
1011 raise Exception, "No node types"
1012 boot_states = self.api.GetBootStates()
1014 raise Exception, "No boot states"
1016 for site_id in self.site_ids:
1017 for i in range(per_site):
1019 node_fields = random_node(node_types,boot_states,self.namelengths)
1020 node_id = self.api.AddNode(site_id, node_fields)
1022 # Should return a unique node_id
1023 assert node_id not in self.node_ids
1024 self.node_ids.append(node_id)
1026 # Add to a random set of node groups
1027 nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
1028 for nodegroup_id in nodegroup_ids:
1029 tagname = self.api.GetNodeGroups([nodegroup_id])[0]['tagname']
1030 self.api.AddNodeTag( node_id, tagname, 'yes' )
1034 node = self.api.GetNodes([node_id])[0]
1035 for field in node_fields:
1036 if field not in tag_fields:
1037 assert node[field] == node_fields[field]
1040 print "Added node", node_id
1042 def UpdateNodes(self):
1044 Make random changes to any nodes we may have added.
1047 node_types = self.api.GetNodeTypes()
1049 raise Exception, "No node types"
1050 boot_states = self.api.GetBootStates()
1052 raise Exception, "No boot states"
1054 for node_id in self.node_ids:
1056 node_fields = random_node(node_types,boot_states,self.namelengths)
1057 self.api.UpdateNode(node_id, node_fields)
1059 node = self.api.GetNodes([node_id])[0]
1061 # Add to a random set of node groups
1062 nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
1063 for nodegroup_id in (set(nodegroup_ids) - set(node['nodegroup_ids'])):
1064 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
1065 tagname = nodegroup['tagname']
1066 node_tags = self.api.GetNodeTags({'node_id':node_id,'tagname':tagname})
1068 self.api.AddNodeTag(node_id,tagname,'yes')
1070 node_tag=node_tags[0]
1071 self.api.UpdateNodeTag(node_tag['node_tag_id'],'yes')
1072 for nodegroup_id in (set(node['nodegroup_ids']) - set(nodegroup_ids)):
1073 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
1074 tagname = nodegroup['tagname']
1075 node_tags = self.api.GetNodeTags({'node_id':node_id,'tagname':tagname})
1077 self.api.AddNodeTag(node_id,tagname,'no')
1079 node_tag=node_tags[0]
1080 self.api.UpdateNodeTag(node_tag['node_tag_id'],'no')
1084 node = self.api.GetNodes([node_id])[0]
1085 for field in node_fields:
1086 if field not in tag_fields:
1087 if node[field] != node_fields[field]:
1088 raise Exception, "Unexpected field %s in node after GetNodes()"%field
1089 assert set(nodegroup_ids) == set(node['nodegroup_ids'])
1091 # again but we are now fetching 'arch' explicitly
1092 node2 = self.api.GetNodes([node_id],node_fields.keys())[0]
1093 for field in node_fields:
1094 if node2[field] != node_fields[field]:
1095 raise Exception, "Unexpected field %s in node after GetNodes(tags)"%field
1098 print "Updated node", node_id
1100 def DeleteNodes(self):
1102 Delete any random nodes we may have added.
1105 for node_id in self.node_ids:
1106 # Remove from node groups
1107 node = self.api.GetNodes([node_id])[0]
1108 for node_tag in self.api.GetNodeTags ( {'node_id': node_id} ):
1109 self.api.UpdateNodeTag(node_tag['node_tag_id'],'')
1112 node = self.api.GetNodes([node_id])[0]
1113 assert not node['nodegroup_ids']
1115 self.api.DeleteNode(node_id)
1118 assert not self.api.GetNodes([node_id])
1121 print "Deleted node", node_id
1124 assert not self.api.GetNodes(self.node_ids)
1128 def AddInterfaces(self, per_node = 1):
1130 Add a number of random network interfaces to each node.
1133 network_methods = self.api.GetNetworkMethods()
1134 if not network_methods:
1135 raise Exception, "No network methods"
1137 network_types = self.api.GetNetworkTypes()
1138 if not network_types:
1139 raise Exception, "No network types"
1141 for node_id in self.node_ids:
1142 for i in range(per_node):
1143 method = random.sample(network_methods, 1)[0]
1144 type = random.sample(network_types, 1)[0]
1147 interface_fields = random_interface(method, type,self.namelengths)
1148 interface_id = self.api.AddInterface(node_id, interface_fields)
1150 # Should return a unique interface_id
1151 assert interface_id not in self.interface_ids
1152 self.interface_ids.append(interface_id)
1156 interface = self.api.GetInterfaces([interface_id])[0]
1157 for field in interface_fields:
1158 assert interface[field] == interface_fields[field]
1161 print "Added interface", interface_id, "to node", node_id
1163 def UpdateInterfaces(self):
1165 Make random changes to any network interfaces we may have added.
1168 network_methods = self.api.GetNetworkMethods()
1169 if not network_methods:
1170 raise Exception, "No network methods"
1172 network_types = self.api.GetNetworkTypes()
1173 if not network_types:
1174 raise Exception, "No network types"
1176 for interface_id in self.interface_ids:
1177 method = random.sample(network_methods, 1)[0]
1178 type = random.sample(network_types, 1)[0]
1181 interface_fields = random_interface(method, type,self.namelengths)
1182 self.api.UpdateInterface(interface_id, interface_fields)
1186 interface = self.api.GetInterfaces([interface_id])[0]
1187 for field in interface_fields:
1188 assert interface[field] == interface_fields[field]
1191 print "Updated interface", interface_id
1193 def DeleteInterfaces(self):
1195 Delete any random network interfaces we may have added.
1198 for interface_id in self.interface_ids:
1199 self.api.DeleteInterface(interface_id)
1202 assert not self.api.GetInterfaces([interface_id])
1205 print "Deleted interface", interface_id
1208 assert not self.api.GetInterfaces(self.interface_ids)
1210 self.interface_ids = []
1212 def AddIlinks (self, n):
1214 Add random links between interfaces.
1218 src = random.sample(self.interface_ids,1)[0]
1219 dst = random.sample(self.interface_ids,1)[0]
1220 ilink_id = self.api.AddIlink (src,dst,
1221 self.ilink_type_ids[i],
1224 assert ilink_id not in self.ilink_ids
1225 self.ilink_ids.append(ilink_id)
1228 print 'Added Ilink',ilink_id,' - attached interface',src,'to',dst
1231 retrieve=GetIlinks({'src_interface_id':src,'dst_interface_id':dst,
1232 'tag_type_id':self.ilink_type_ids[i]})
1233 assert ilink_id==retrieve[0]['ilink_id']
1236 def UpdateIlinks (self):
1238 for ilink_id in self.ilink_ids:
1239 new_value=random_ilink()
1240 self.api.UpdateIlink(ilink_id,new_value)
1243 ilink=self.api.GetIlinks([ilink_id])[0]
1244 assert ilink['value'] == new_value
1247 print 'Updated Ilink',ilink_id
1249 def DeleteIlinks (self):
1250 for ilink_id in self.ilink_ids:
1251 self.api.DeleteIlink(ilink_id)
1254 assert not self.api.GetIlinks({'ilink_id':ilink_id})
1257 print 'Deleted Ilink',ilink_id
1260 assert not self.api.GetIlinks(self.ilink_ids)
1265 def AddPCUs(self, per_site = 1):
1267 Add a number of random PCUs to each site. Each node at the
1268 site will be added to a port on the PCU if AddNodes() was
1272 for site_id in self.site_ids:
1273 for i in range(per_site):
1275 pcu_fields = random_pcu(self.namelengths)
1276 pcu_id = self.api.AddPCU(site_id, pcu_fields)
1278 # Should return a unique pcu_id
1279 assert pcu_id not in self.pcu_ids
1280 self.pcu_ids.append(pcu_id)
1282 # Add each node at this site to a different port on this PCU
1283 site = self.api.GetSites([site_id])[0]
1284 port = randint(1, 10)
1285 for node_id in site['node_ids']:
1286 self.api.AddNodeToPCU(node_id, pcu_id, port)
1291 pcu = self.api.GetPCUs([pcu_id])[0]
1292 for field in pcu_fields:
1293 assert pcu[field] == pcu_fields[field]
1296 print "Added PCU", pcu_id, "to site", site_id
1298 def UpdatePCUs(self):
1300 Make random changes to any PCUs we may have added.
1303 for pcu_id in self.pcu_ids:
1305 pcu_fields = random_pcu(self.namelengths)
1306 self.api.UpdatePCU(pcu_id, pcu_fields)
1310 pcu = self.api.GetPCUs([pcu_id])[0]
1311 for field in pcu_fields:
1312 assert pcu[field] == pcu_fields[field]
1315 print "Updated PCU", pcu_id
1317 def DeletePCUs(self):
1319 Delete any random nodes we may have added.
1322 for pcu_id in self.pcu_ids:
1323 # Remove nodes from PCU
1324 pcu = self.api.GetPCUs([pcu_id])[0]
1325 for node_id in pcu['node_ids']:
1326 self.api.DeleteNodeFromPCU(node_id, pcu_id)
1329 pcu = self.api.GetPCUs([pcu_id])[0]
1330 assert not pcu['node_ids']
1332 self.api.DeletePCU(pcu_id)
1335 assert not self.api.GetPCUs([pcu_id])
1338 print "Deleted PCU", pcu_id
1341 assert not self.api.GetPCUs(self.pcu_ids)
1345 def AddConfFiles(self, n = 10):
1347 Add a number of random global configuration files.
1353 # Add a random configuration file
1354 conf_files.append(random_conf_file())
1357 # Add a nodegroup override file
1358 nodegroup_conf_file = conf_files[0].copy()
1359 nodegroup_conf_file['source'] = randpath(255)
1360 conf_files.append(nodegroup_conf_file)
1362 # Add a node override file
1363 node_conf_file = conf_files[0].copy()
1364 node_conf_file['source'] = randpath(255)
1365 conf_files.append(node_conf_file)
1367 for conf_file_fields in conf_files:
1368 conf_file_id = self.api.AddConfFile(conf_file_fields)
1370 # Should return a unique conf_file_id
1371 assert conf_file_id not in self.conf_file_ids
1372 self.conf_file_ids.append(conf_file_id)
1375 if conf_file_fields == nodegroup_conf_file and self.nodegroup_ids:
1376 nodegroup_id = random.sample(self.nodegroup_ids, 1)[0]
1377 self.api.AddConfFileToNodeGroup(conf_file_id, nodegroup_id)
1382 if conf_file_fields == node_conf_file and self.node_ids:
1383 node_id = random.sample(self.node_ids, 1)[0]
1384 self.api.AddConfFileToNode(conf_file_id, node_id)
1389 # Check configuration file
1390 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1391 for field in conf_file_fields:
1392 assert conf_file[field] == conf_file_fields[field]
1395 print "Added configuration file", conf_file_id,
1396 if nodegroup_id is not None:
1397 print "to node group", nodegroup_id,
1398 elif node_id is not None:
1399 print "to node", node_id,
1402 def UpdateConfFiles(self):
1404 Make random changes to any configuration files we may have added.
1407 for conf_file_id in self.conf_file_ids:
1408 # Update configuration file
1409 conf_file_fields = random_conf_file()
1410 # Do not update dest so that it remains an override if set
1411 if 'dest' in conf_file_fields:
1412 del conf_file_fields['dest']
1413 self.api.UpdateConfFile(conf_file_id, conf_file_fields)
1416 # Check configuration file
1417 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1418 for field in conf_file_fields:
1419 assert conf_file[field] == conf_file_fields[field]
1422 print "Updated configuration file", conf_file_id
1424 def DeleteConfFiles(self):
1426 Delete any random configuration files we may have added.
1429 for conf_file_id in self.conf_file_ids:
1430 self.api.DeleteConfFile(conf_file_id)
1433 assert not self.api.GetConfFiles([conf_file_id])
1436 print "Deleted configuration file", conf_file_id
1439 assert not self.api.GetConfFiles(self.conf_file_ids)
1441 self.conf_file_ids = []
1443 def AddTagTypes(self,n_sa,n_ng,n_il):
1445 Add as many tag types as there are nodegroups,
1446 will use value=yes for each nodegroup
1449 roles = self.api.GetRoles()
1451 raise Exception, "No roles"
1452 role_ids = [role['role_id'] for role in roles]
1454 for i in range (n_sa + n_ng + n_il):
1455 tag_type_fields = random_tag_type (role_ids)
1456 tag_type_id = self.api.AddTagType (tag_type_fields)
1458 assert tag_type_id not in \
1459 self.slice_type_ids + \
1460 self.nodegroup_type_ids + \
1463 tt_role_ids=random_roles(role_ids)
1464 for tt_role_id in tt_role_ids:
1465 self.api.AddRoleToTagType(tt_role_id,tag_type_id)
1468 self.slice_type_ids.append(tag_type_id)
1469 elif i < n_sa+n_ng :
1470 self.nodegroup_type_ids.append(tag_type_id)
1472 self.ilink_type_ids.append(tag_type_id)
1475 tag_type = self.api.GetTagTypes([tag_type_id])[0]
1476 for field in tag_type_fields:
1477 assert tag_type[field] == tag_type_fields[field]
1478 for tt_role_id in tt_role_ids:
1479 assert tt_role_id in tag_type['role_ids']
1481 print "Created tag type", tag_type_id
1483 def UpdateTagTypes(self):
1485 Make random changes to any slice attribute types we may have added.
1488 roles = self.api.GetRoles()
1490 raise Exception, "No roles"
1491 role_ids = [role['role_id'] for role in roles]
1493 for tag_type_id in self.slice_type_ids + self.nodegroup_type_ids + self.ilink_type_ids:
1494 # Update slice attribute type
1495 tag_type_fields = random_tag_type(role_ids)
1496 self.api.UpdateTagType(tag_type_id, tag_type_fields)
1499 # Check slice attribute type
1500 tag_type = self.api.GetTagTypes([tag_type_id])[0]
1501 for field in tag_type_fields:
1502 assert tag_type[field] == tag_type_fields[field]
1504 print "Updated tag type", tag_type_id
1506 def DeleteTagTypes(self):
1508 Delete any random slice attribute types we may have added.
1511 for tag_type_id in self.slice_type_ids + self.nodegroup_type_ids + self.ilink_type_ids:
1512 self.api.DeleteTagType(tag_type_id)
1515 assert not self.api.GetTagTypes([tag_type_id])
1518 print "Deleted tag type", tag_type_id
1521 assert not self.api.GetTagTypes(self.slice_type_ids+self.nodegroup_type_ids+self.ilink_type_ids)
1523 self.slice_type_ids = []
1524 self.nodegroup_type_ids = []
1526 def AddSlices(self, per_site = 10):
1528 Add a number of random slices per site.
1531 for site in self.api.GetSites(self.site_ids):
1532 for i in range(min(per_site, site['max_slices'])):
1534 slice_fields = random_slice(site['login_base'],self.namelengths)
1535 slice_id = self.api.AddSlice(slice_fields)
1537 # Should return a unique slice_id
1538 assert slice_id not in self.slice_ids
1539 self.slice_ids.append(slice_id)
1541 # Add slice to a random set of nodes
1542 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1544 self.api.AddSliceToNodes(slice_id, node_ids)
1546 # Add random set of site users to slice
1547 person_ids = random.sample(site['person_ids'], randint(0, len(site['person_ids'])))
1548 for person_id in person_ids:
1549 self.api.AddPersonToSlice(person_id, slice_id)
1553 slice = self.api.GetSlices([slice_id])[0]
1554 for field in slice_fields:
1555 assert slice[field] == slice_fields[field]
1557 assert set(node_ids) == set(slice['node_ids'])
1558 assert set(person_ids) == set(slice['person_ids'])
1561 print "Added slice", slice_id, "to site", site['site_id'],
1563 print "and nodes", node_ids,
1566 print "Added users", site['person_ids'], "to slice", slice_id
1568 def UpdateSlices(self):
1570 Make random changes to any slices we may have added.
1573 for slice_id in self.slice_ids:
1575 slice_fields = random_slice("unused",self.namelengths)
1576 # Cannot change slice name
1577 if 'name' in slice_fields:
1578 del slice_fields['name']
1579 self.api.UpdateSlice(slice_id, slice_fields)
1581 slice = self.api.GetSlices([slice_id])[0]
1583 # Add slice to a random set of nodes
1584 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1585 self.api.AddSliceToNodes(slice_id, list(set(node_ids) - set(slice['node_ids'])))
1586 self.api.DeleteSliceFromNodes(slice_id, list(set(slice['node_ids']) - set(node_ids)))
1588 # Add random set of users to slice
1589 person_ids = random.sample(self.person_ids, randint(0, len(self.person_ids)))
1590 for person_id in (set(person_ids) - set(slice['person_ids'])):
1591 self.api.AddPersonToSlice(person_id, slice_id)
1592 for person_id in (set(slice['person_ids']) - set(person_ids)):
1593 self.api.DeletePersonFromSlice(person_id, slice_id)
1596 slice = self.api.GetSlices([slice_id])[0]
1597 for field in slice_fields:
1598 assert slice[field] == slice_fields[field]
1599 assert set(node_ids) == set(slice['node_ids'])
1600 assert set(person_ids) == set(slice['person_ids'])
1603 print "Updated slice", slice_id
1604 print "Added nodes", node_ids, "to slice", slice_id
1605 print "Added persons", person_ids, "to slice", slice_id
1607 def DeleteSlices(self):
1609 Delete any random slices we may have added.
1612 for slice_id in self.slice_ids:
1613 self.api.DeleteSlice(slice_id)
1616 assert not self.api.GetSlices([slice_id])
1619 print "Deleted slice", slice_id
1622 assert not self.api.GetSlices(self.slice_ids)
1626 def AddSliceTags(self, per_slice = 2):
1628 Add a number of random slices per site.
1631 if not self.slice_type_ids:
1634 for slice_id in self.slice_ids:
1635 slice = self.api.GetSlices([slice_id])[0]
1637 for i in range(per_slice):
1638 # Set a random slice/sliver attribute
1639 for tag_type_id in random.sample(self.slice_type_ids, 1):
1640 value = randstr(16, letters + '_' + digits)
1641 # Make it a sliver attribute with 50% probability
1642 if slice['node_ids']:
1643 node_id = random.sample(slice['node_ids'] + [None] * len(slice['node_ids']), 1)[0]
1647 # Add slice attribute
1649 slice_tag_id = self.api.AddSliceTag(slice_id, tag_type_id, value)
1651 slice_tag_id = self.api.AddSliceTag(slice_id, tag_type_id, value, node_id)
1653 # Should return a unique slice_tag_id
1654 assert slice_tag_id not in self.slice_tag_ids
1655 self.slice_tag_ids.append(slice_tag_id)
1658 # Check slice attribute
1659 slice_tag = self.api.GetSliceTags([slice_tag_id])[0]
1660 for field in 'tag_type_id', 'slice_id', 'node_id', 'slice_tag_id', 'value':
1661 assert slice_tag[field] == locals()[field]
1664 print "Added slice attribute", slice_tag_id, "of type", tag_type_id,
1665 if node_id is not None:
1666 print "to node", node_id,
1669 def UpdateSliceTags(self):
1671 Make random changes to any slice attributes we may have added.
1674 for slice_tag_id in self.slice_tag_ids:
1675 # Update slice attribute
1676 value = randstr(16, letters + '_' + digits)
1677 self.api.UpdateSliceTag(slice_tag_id, value)
1679 # Check slice attribute again
1680 slice_tag = self.api.GetSliceTags([slice_tag_id])[0]
1681 assert slice_tag['value'] == value
1684 print "Updated slice attribute", slice_tag_id
1686 def DeleteSliceTags(self):
1688 Delete any random slice attributes we may have added.
1691 for slice_tag_id in self.slice_tag_ids:
1692 self.api.DeleteSliceTag(slice_tag_id)
1695 assert not self.api.GetSliceTags([slice_tag_id])
1698 print "Deleted slice attribute", slice_tag_id
1701 assert not self.api.GetSliceTags(self.slice_tag_ids)
1703 self.slice_tag_ids = []
1705 # convenience for cleaning up
1706 # not exactly accurate -- use on test plcs only
1707 def WipeSitesFromLength(self):
1708 for site in self.api.GetSites():
1709 abbrev=site['abbreviated_name']
1710 # print 'matching',len(abbrev),'against',self.namelengths['abbreviated_name']
1711 if len(abbrev)==self.namelengths['abbreviated_name']:
1712 # if len(abbrev)==17:
1713 print 'wiping site %d (%s)'%(site['site_id'],site['name'])
1714 self.api.DeleteSite(site['site_id'])
1717 parser = OptionParser()
1718 parser.add_option("-c", "--check", action = "store_true", default = False,
1719 help = "Check most actions (default: %default)")
1720 parser.add_option("-q", "--quiet", action = "store_true", default = False,
1721 help = "Be quiet (default: %default)")
1722 parser.add_option("-p","--preserve", action="store_true", default =False,
1723 help = "Do not delete created objects")
1724 parser.add_option("-t", "--tiny", action = "store_true", default = False,
1725 help = "Run a tiny test (default: %default)")
1726 parser.add_option("-l", "--large", action = "store_true", default = False,
1727 help = "Run a large test (default: %default)")
1728 parser.add_option("-x", "--xlarge", action = "store_true", default = False,
1729 help = "Run an XL test (default: %default)")
1730 parser.add_option("-s", "--short-names", action="store_true", dest="short_names", default = False,
1731 help = "Generate smaller names for checking UI rendering")
1732 parser.add_option ("-f", "--foreign", action="store_true", dest="federating", default = False,
1733 help = "Create a fake peer and add items in it (no update, no delete)")
1734 parser.add_option ("-w", "--wipe", action="store_true", dest="wipe", default = False,
1735 help = "Wipe sites whose abbrev matches what the tests created")
1736 (options, args) = parser.parse_args()
1738 test = Test(api = Shell(),
1739 check = options.check,
1740 verbose = not options.quiet,
1741 preserve = options.preserve,
1742 federating = options.federating)
1744 if options.short_names:
1745 test.namelengths = Test.namelengths_short
1747 test.namelengths = Test.namelengths_default
1750 test.WipeSitesFromLength()
1754 sizes = Test.sizes_tiny
1756 sizes = Test.sizes_large
1757 elif options.xlarge:
1758 sizes = Test.sizes_xlarge
1760 sizes = Test.sizes_default
1763 if __name__ == "__main__":