3 # Test script utility class
5 # Mark Huang <mlhuang@cs.princeton.edu>
6 # Copyright (C) 2006 The Trustees of Princeton University
11 from pprint import pprint
12 from string import letters, digits, punctuation, whitespace
13 from traceback import print_exc
14 from optparse import OptionParser
21 from PLC.Shell import Shell
23 from random import Random
26 # note about namelengths
27 # original version uses full lengths for all fields for testing overflows and things
28 # however for a realistic test, involving a web UI, this is not appropriate, so we
29 # use smaller identifiers
31 def randfloat(min = 0.0, max = 1.0):
32 return float(min) + (random.random() * (float(max) - float(min)))
34 def randint(min = 0, max = 1):
35 return int(randfloat(min, max + 1))
37 # See "2.2 Characters" in the XML specification:
39 # #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
41 # [#x7F-#x84], [#x86-#x9F], [#xFDD0-#xFDDF]
44 ascii_xml_chars = map(unichr, [0x9, 0xA])
45 # xmlrpclib uses xml.parsers.expat, which always converts either '\r'
46 # (#xD) or '\n' (#xA) to '\n'. So avoid using '\r', too, if this is
48 if xmlrpclib.loads(xmlrpclib.dumps(('\r',)))[0][0] == '\r':
49 ascii_xml_chars.append('\r')
50 ascii_xml_chars += map(unichr, xrange(0x20, 0x7F - 1))
51 low_xml_chars = list(ascii_xml_chars)
52 low_xml_chars += map(unichr, xrange(0x84 + 1, 0x86 - 1))
53 low_xml_chars += map(unichr, xrange(0x9F + 1, 0xFF))
54 valid_xml_chars = list(low_xml_chars)
55 valid_xml_chars += map(unichr, xrange(0xFF + 1, 0xD7FF))
56 valid_xml_chars += map(unichr, xrange(0xE000, 0xFDD0 - 1))
57 valid_xml_chars += map(unichr, xrange(0xFDDF + 1, 0xFFFD))
59 def randstr(length, pool = valid_xml_chars, encoding = "utf-8"):
60 sample = random.sample(pool, min(length, len(pool)))
63 bytes = len(s.encode(encoding))
67 sample += random.sample(pool, min(length - bytes, len(pool)))
68 random.shuffle(sample)
73 def randhostname(namelengths):
74 # 1. Each part begins and ends with a letter or number.
75 # 2. Each part except the last can contain letters, numbers, or hyphens.
76 # 3. Each part is between 1 and 64 characters, including the trailing dot.
77 # 4. At least two parts.
78 # 5. Last part can only contain between 2 and 6 letters.
79 hostname = 'a' + randstr(namelengths['hostname1'], letters + digits + '-') + '1.' + \
80 'b' + randstr(namelengths['hostname1'], letters + digits + '-') + '2.' + \
81 'c' + randstr(namelengths['hostname2'], letters)
86 for i in range(randint(1, 10)):
87 parts.append(randstr(randint(1, 30), ascii_xml_chars))
88 return u'/'.join(parts)[0:length]
90 def randemail(namelengths):
91 return (randstr(namelengths['email'], letters + digits) + "@" + randhostname(namelengths)).lower()
93 def randkey(namelengths,bits = 2048):
94 ssh_key_types = ["ssh-dss", "ssh-rsa"]
95 key_type = random.sample(ssh_key_types, 1)[0]
96 return ' '.join([key_type,
97 base64.b64encode(''.join(randstr(bits / 8).encode("utf-8"))),
98 randemail(namelengths)])
102 'peername': randstr(24,letters + ' ' + digits),
103 'peer_url': "https://" + randhostname ({'hostname1':8,'hostname2':3}) + ":443/PLCAPI/",
104 'key' : randstr(1024,letters+digits),
105 'cacert' : randstr(1024,letters+digits),
106 'shortname' : randstr(1,letters) + 'LAB',
107 'hrn_root' : 'planetlab.' + randstr (3,letters),
110 def random_site(namelengths):
112 sitename=randstr(namelengths['sitename'],namelengths['sitename_contents'])
114 sitename=randstr(namelengths['sitename'])
116 abbreviated_name=randstr(namelengths['abbreviated_name'],namelengths['abbreviated_name_contents'])
118 abbreviated_name=randstr(namelengths['abbreviated_name'])
122 'abbreviated_name': abbreviated_name,
123 'login_base': randstr(namelengths['login_base'], letters).lower(),
124 'latitude': int(randfloat(-90.0, 90.0) * 1000) / 1000.0,
125 'longitude': int(randfloat(-180.0, 180.0) * 1000) / 1000.0,
128 def random_address_type():
131 'description': randstr(254),
134 def random_address():
136 'line1': randstr(254),
137 'line2': randstr(254),
138 'line3': randstr(254),
139 'city': randstr(254),
140 'state': randstr(254),
141 'postalcode': randstr(64),
142 'country': randstr(128),
145 def random_person(namelengths):
147 'first_name': randstr(namelengths['first_name']),
148 'last_name': randstr(namelengths['last_name']),
149 'email': randemail(namelengths),
151 # Accounts are disabled by default
153 'password': randstr(254),
156 def random_key(key_types,namelengths):
158 'key_type': random.sample(key_types, 1)[0],
159 'key': randkey(namelengths)
162 def random_tag_type (role_ids):
163 return {'tagname': randstr(12,letters+digits),
164 'category':randstr(4,letters+digits)+'/'+randstr(6,letters+digits),
165 'min_role_id': random.sample(role_ids, 1)[0],
166 'description' : randstr(128,letters+digits+whitespace+punctuation),
169 def random_nodegroup():
170 return {'groupname' : randstr(30, letters+digits+whitespace) }
173 def random_node(node_types,boot_states,namelengths):
175 'hostname': randhostname(namelengths),
176 'node_type': random.sample(node_types,1)[0],
177 'boot_state': random.sample(boot_states, 1)[0],
178 'model': randstr(namelengths['model']),
179 'version': randstr(64),
180 # for testing node tags
184 def random_interface(method, type,namelengths):
188 'bwlimit': randint(500000, 10000000),
192 ip = randint(0, 0xffffffff)
193 netmask = (0xffffffff << randint(2, 31)) & 0xffffffff
194 network = ip & netmask
195 broadcast = ((ip & netmask) | ~netmask) & 0xffffffff
196 gateway = randint(network + 1, broadcast - 1)
197 dns1 = randint(0, 0xffffffff)
199 for field in 'ip', 'netmask', 'network', 'broadcast', 'gateway', 'dns1':
200 interface_fields[field] = socket.inet_ntoa(struct.pack('>L', locals()[field]))
202 interface_fields['hostname']=randhostname(namelengths);
204 return interface_fields
209 def random_pcu(namelengths):
211 'hostname': randhostname(namelengths),
212 'ip': socket.inet_ntoa(struct.pack('>L', randint(0, 0xffffffff))),
213 'protocol': randstr(16),
214 'username': randstr(254),
215 'password': randstr(254),
216 'notes': randstr(254),
217 'model': randstr(32),
220 def random_conf_file():
222 'enabled': bool(randint()),
223 'source': randpath(255),
224 'dest': randpath(255),
225 'file_permissions': "%#o" % randint(0, 512),
226 'file_owner': randstr(32, letters + '_' + digits),
227 'file_group': randstr(32, letters + '_' + digits),
228 'preinstall_cmd': randpath(100),
229 'postinstall_cmd': randpath(100),
230 'error_cmd': randpath(100),
231 'ignore_cmd_errors': bool(randint()),
232 'always_update': bool(randint()),
235 def random_slice(login_base,namelengths):
237 'name': login_base + "_" + randstr(11, letters).lower(),
238 'url': "http://" + randhostname(namelengths) + "/",
239 'description': randstr(2048),
246 'addresses_per_site': 1,
247 'persons_per_site': 1,
248 'keys_per_person': 1,
252 'interfaces_per_node': 1,
256 'slices_per_site': 1,
257 'attributes_per_slice': 1,
263 'addresses_per_site': 2,
264 'persons_per_site': 4,
265 'keys_per_person': 2,
269 'interfaces_per_node': 1,
273 'slices_per_site': 4,
274 'attributes_per_slice': 2,
280 'addresses_per_site': 2,
281 'persons_per_site': 5,
282 'keys_per_person': 2,
286 'interfaces_per_node': 2,
290 'slices_per_site': 10,
291 'attributes_per_slice': 4,
297 'addresses_per_site': 2,
298 'persons_per_site': 5,
299 'keys_per_person': 2,
303 'interfaces_per_node': 2,
307 'slices_per_site': 10,
308 'attributes_per_slice': 4,
311 namelengths_default = {
316 'abbreviated_name':50,
323 namelengths_short = {
328 'sitename_contents':letters+digits+whitespace+punctuation,
329 'abbreviated_name':24,
330 'abbreviated_name_contents':letters+digits+whitespace+punctuation,
337 def __init__(self, api, check, verbose, preserve, federating):
340 self.verbose = verbose
341 self.preserve = preserve
342 self.federating = federating
345 self.address_type_ids = []
346 self.address_ids = []
349 self.slice_type_ids = []
350 self.nodegroup_type_ids = []
351 self.ilink_type_ids = []
352 self.nodegroup_ids = []
354 self.interface_ids = []
357 self.conf_file_ids = []
359 self.slice_tag_ids = []
361 def Cardinals (self):
362 return [len(x) for x in (
363 self.api.GetNodes({},['node_id']),
364 self.api.GetSites({},['site_id']),
365 self.api.GetPersons({},['person_id']),
366 self.api.GetSlices({},['slice_id']),
369 def Run(self, **kwds):
371 Run a complete database and API consistency test. Populates
372 the database with a set of random entities, updates them, then
373 deletes them. Examples:
375 test.Run() # Defaults
376 test.Run(**Test.sizes_default) # Defaults
377 test.Run(**Test.sizes_tiny) # Tiny set
378 test.Run(sites = 123, slices_per_site = 4) # Defaults with overrides
381 cardinals_before=self.Cardinals()
382 print 'Cardinals before test (n,s,p,sl)',cardinals_before
385 # if federating : we're done
387 if self.federating or self.preserve:
388 print 'Preserving - update & delete skipped'
393 cardinals_after=self.Cardinals()
394 print 'Cardinals after test (n,s,p,sl)',cardinals_after
396 if cardinals_before != cardinals_after:
397 raise Exception, 'cardinals before and after differ - check deletion mechanisms'
399 def Add(self, **kwds):
401 Populate the database with a set of random entities. Examples:
406 sizes = self.sizes_default.copy()
409 if not self.federating:
410 self.AddSites(sizes['sites'])
411 self.AddAddressTypes(sizes['address_types'])
412 self.AddAddresses(sizes['addresses_per_site'])
413 self.AddPersons(sizes['persons_per_site'])
414 self.AddKeys(sizes['keys_per_person'])
415 self.AddTagTypes(sizes['slice_tags'],sizes['nodegroups'],sizes['ilinks'])
416 self.AddNodeGroups(sizes['nodegroups'])
417 self.AddNodes(sizes['nodes_per_site'])
418 self.AddInterfaces(sizes['interfaces_per_node'])
419 self.AddIlinks (sizes['ilinks'])
420 self.AddPCUs(sizes['pcus_per_site'])
421 self.AddConfFiles(sizes['conf_files'])
422 self.AddSlices(sizes['slices_per_site'])
423 self.AddSliceTags(sizes['attributes_per_slice'])
427 self.AddSites(sizes['sites'])
428 self.AddPersons(sizes['persons_per_site'])
429 self.AddKeys(sizes['keys_per_person'])
430 self.AddNodes(sizes['nodes_per_site'])
431 self.AddSlices(sizes['slices_per_site'])
432 # create peer and add newly created entities
438 self.UpdateAddressTypes()
439 self.UpdateAddresses()
442 self.UpdateTagTypes()
443 self.UpdateNodeGroups()
445 self.UpdateInterfaces()
448 self.UpdateConfFiles()
450 self.UpdateSliceTags()
453 self.DeleteSliceTags()
456 self.DeleteConfFiles()
459 self.DeleteInterfaces()
462 self.DeleteNodeGroups()
463 self.DeleteTagTypes()
464 self.DeleteAddresses()
465 self.DeleteAddressTypes()
468 # record current (old) objects
469 def RecordStatus (self):
470 self.old_site_ids = [ s['site_id'] for s in self.api.GetSites({},['site_id']) ]
471 self.old_person_ids = [ s['person_id'] for s in self.api.GetPersons({},['person_id']) ]
472 self.old_key_ids = [ s['key_id'] for s in self.api.GetKeys({},['key_id']) ]
473 self.old_node_ids = [ s['node_id'] for s in self.api.GetNodes({},['node_id']) ]
474 self.old_slice_ids = [ s['slice_id'] for s in self.api.GetSlices({},['slice_id']) ]
477 peer_id=self.api.AddPeer (random_peer())
478 peer = GetPeers([peer_id])[0]
480 print "Added peer",peer_id
482 # add new sites (the ones not in self.site_ids) in the peer
484 for site in self.api.GetSites ({'~site_id':self.old_site_ids}):
485 peer.add_site(site,site['site_id'])
486 for person in self.api.GetPersons ({'~person_id':self.old_person_ids}):
487 peer.add_person(person,person['person_id'])
488 for key in self.api.GetKeys ({'~key_id':self.old_key_ids}):
489 peer.add_key(key,key['key_id'])
490 for node in self.api.GetNodes ({'~node_id':self.old_node_ids}):
491 peer.add_node(node,node['node_id'])
492 for slice in self.api.GetSlices ({'~slice_id':self.old_slice_ids}):
493 peer.add_slice(slice,slice['slice_id'])
495 def AddSites(self, n = 10):
497 Add a number of random sites.
502 site_fields = random_site(self.namelengths)
503 site_id = self.api.AddSite(site_fields)
505 # Should return a unique site_id
506 assert site_id not in self.site_ids
507 self.site_ids.append(site_id)
509 # Enable slice creation
510 site_fields['max_slices'] = randint(1, 10)
511 self.api.UpdateSite(site_id, site_fields)
515 site = self.api.GetSites([site_id])[0]
516 for field in site_fields:
517 assert site[field] == site_fields[field]
520 print "Added site", site_id
522 def UpdateSites(self):
524 Make random changes to any sites we may have added.
527 for site_id in self.site_ids:
529 site_fields = random_site(self.namelengths)
530 # Do not change login_base
531 if 'login_base' in site_fields:
532 del site_fields['login_base']
533 self.api.UpdateSite(site_id, site_fields)
537 site = self.api.GetSites([site_id])[0]
538 for field in site_fields:
539 assert site[field] == site_fields[field]
542 print "Updated site", site_id
544 def DeleteSites(self):
546 Delete any random sites we may have added.
549 for site_id in self.site_ids:
550 self.api.DeleteSite(site_id)
553 assert not self.api.GetSites([site_id])
556 print "Deleted site", site_id
559 assert not self.api.GetSites(self.site_ids)
563 def AddAddressTypes(self, n = 2):
565 Add a number of random address types.
569 address_type_fields = random_address_type()
570 address_type_id = self.api.AddAddressType(address_type_fields)
572 # Should return a unique address_type_id
573 assert address_type_id not in self.address_type_ids
574 self.address_type_ids.append(address_type_id)
578 address_type = self.api.GetAddressTypes([address_type_id])[0]
579 for field in address_type_fields:
580 assert address_type[field] == address_type_fields[field]
583 print "Added address type", address_type_id
585 def UpdateAddressTypes(self):
587 Make random changes to any address types we may have added.
590 for address_type_id in self.address_type_ids:
591 # Update address_type
592 address_type_fields = random_address_type()
593 self.api.UpdateAddressType(address_type_id, address_type_fields)
597 address_type = self.api.GetAddressTypes([address_type_id])[0]
598 for field in address_type_fields:
599 assert address_type[field] == address_type_fields[field]
602 print "Updated address_type", address_type_id
604 def DeleteAddressTypes(self):
606 Delete any random address types we may have added.
609 for address_type_id in self.address_type_ids:
610 self.api.DeleteAddressType(address_type_id)
613 assert not self.api.GetAddressTypes([address_type_id])
616 print "Deleted address type", address_type_id
619 assert not self.api.GetAddressTypes(self.address_type_ids)
621 self.address_type_ids = []
623 def AddAddresses(self, per_site = 2):
625 Add a number of random addresses to each site.
628 for site_id in self.site_ids:
629 for i in range(per_site):
630 address_fields = random_address()
631 address_id = self.api.AddSiteAddress(site_id, address_fields)
633 # Should return a unique address_id
634 assert address_id not in self.address_ids
635 self.address_ids.append(address_id)
637 # Add random address type
638 if self.address_type_ids:
639 for address_type_id in random.sample(self.address_type_ids, 1):
640 self.api.AddAddressTypeToAddress(address_type_id, address_id)
644 address = self.api.GetAddresses([address_id])[0]
645 for field in address_fields:
646 assert address[field] == address_fields[field]
649 print "Added address", address_id, "to site", site_id
651 def UpdateAddresses(self):
653 Make random changes to any addresses we may have added.
656 for address_id in self.address_ids:
658 address_fields = random_address()
659 self.api.UpdateAddress(address_id, address_fields)
663 address = self.api.GetAddresses([address_id])[0]
664 for field in address_fields:
665 assert address[field] == address_fields[field]
668 print "Updated address", address_id
670 def DeleteAddresses(self):
672 Delete any random addresses we may have added.
675 for address_id in self.address_ids:
676 # Remove address types
677 address = self.api.GetAddresses([address_id])[0]
678 for address_type_id in address['address_type_ids']:
679 self.api.DeleteAddressTypeFromAddress(address_type_id, address_id)
682 address = self.api.GetAddresses([address_id])[0]
683 assert not address['address_type_ids']
685 self.api.DeleteAddress(address_id)
688 assert not self.api.GetAddresses([address_id])
691 print "Deleted address", address_id
694 assert not self.api.GetAddresses(self.address_ids)
696 self.address_ids = []
698 def AddPersons(self, per_site = 10):
700 Add a number of random users to each site.
703 for site_id in self.site_ids:
704 for i in range(per_site):
706 person_fields = random_person(self.namelengths)
707 person_id = self.api.AddPerson(person_fields)
709 # Should return a unique person_id
710 assert person_id not in self.person_ids
711 self.person_ids.append(person_id)
715 person = self.api.GetPersons([person_id])[0]
716 for field in person_fields:
717 if field != 'password':
718 assert person[field] == person_fields[field]
720 auth = {'AuthMethod': "password",
721 'Username': person_fields['email'],
722 'AuthString': person_fields['password']}
725 # Check that user is disabled
727 assert not self.api.AuthCheck(auth)
731 # Add random set of roles
732 role_ids = random.sample([20, 30, 40], randint(1, 3))
733 for role_id in role_ids:
734 self.api.AddRoleToPerson(role_id, person_id)
737 person = self.api.GetPersons([person_id])[0]
738 assert set(role_ids) == set(person['role_ids'])
741 self.api.UpdatePerson(person_id, {'enabled': True})
744 # Check that user is enabled
745 assert self.api.AuthCheck(auth)
747 # Associate user with site
748 self.api.AddPersonToSite(person_id, site_id)
749 self.api.SetPersonPrimarySite(person_id, site_id)
752 person = self.api.GetPersons([person_id])[0]
753 assert person['site_ids'][0] == site_id
756 print "Added user", person_id, "to site", site_id
758 def UpdatePersons(self):
760 Make random changes to any users we may have added.
763 for person_id in self.person_ids:
765 person_fields = random_person(self.namelengths)
767 person_fields['enabled'] = True
768 self.api.UpdatePerson(person_id, person_fields)
772 person = self.api.GetPersons([person_id])[0]
773 for field in person_fields:
774 if field != 'password':
775 assert person[field] == person_fields[field]
778 print "Updated person", person_id
780 person = self.api.GetPersons([person_id])[0]
782 # Associate user with a random set of sites
783 site_ids = random.sample(self.site_ids, randint(0, len(self.site_ids)))
784 for site_id in (set(site_ids) - set(person['site_ids'])):
785 self.api.AddPersonToSite(person_id, site_id)
786 for site_id in (set(person['site_ids']) - set(site_ids)):
787 self.api.DeletePersonFromSite(person_id, site_id)
790 self.api.SetPersonPrimarySite(person_id, site_ids[0])
793 person = self.api.GetPersons([person_id])[0]
794 assert set(site_ids) == set(person['site_ids'])
797 print "Updated person", person_id, "to sites", site_ids
799 def DeletePersons(self):
801 Delete any random users we may have added.
804 for person_id in self.person_ids:
806 person = self.api.GetPersons([person_id])[0]
807 for site_id in person['site_ids']:
808 self.api.DeletePersonFromSite(person_id, site_id)
811 person = self.api.GetPersons([person_id])[0]
812 assert not person['site_ids']
815 for role_id in person['role_ids']:
816 self.api.DeleteRoleFromPerson(role_id, person_id)
819 person = self.api.GetPersons([person_id])[0]
820 assert not person['role_ids']
823 self.api.UpdatePerson(person_id, {'enabled': False})
826 person = self.api.GetPersons([person_id])[0]
827 assert not person['enabled']
830 self.api.DeletePerson(person_id)
833 assert not self.api.GetPersons([person_id])
836 print "Deleted user", person_id
839 assert not self.api.GetPersons(self.person_ids)
843 def AddKeys(self, per_person = 2):
845 Add a number of random keys to each user.
848 key_types = self.api.GetKeyTypes()
850 raise Exception, "No key types"
852 for person_id in self.person_ids:
853 for i in range(per_person):
855 key_fields = random_key(key_types,self.namelengths)
856 key_id = self.api.AddPersonKey(person_id, key_fields)
858 # Should return a unique key_id
859 assert key_id not in self.key_ids
860 self.key_ids.append(key_id)
864 key = self.api.GetKeys([key_id])[0]
865 for field in key_fields:
866 assert key[field] == key_fields[field]
868 # Add and immediately blacklist a key
869 key_fields = random_key(key_types,self.namelengths)
870 key_id = self.api.AddPersonKey(person_id, key_fields)
872 self.api.BlacklistKey(key_id)
874 # Is effectively deleted
875 assert not self.api.GetKeys([key_id])
877 # Cannot be added again
879 key_id = self.api.AddPersonKey(person_id, key_fields)
885 print "Added key", key_id, "to user", person_id
887 def UpdateKeys(self):
889 Make random changes to any keys we may have added.
892 key_types = self.api.GetKeyTypes()
894 raise Exception, "No key types"
896 for key_id in self.key_ids:
898 key_fields = random_key(key_types,self.namelengths)
899 self.api.UpdateKey(key_id, key_fields)
903 key = self.api.GetKeys([key_id])[0]
904 for field in key_fields:
905 assert key[field] == key_fields[field]
908 print "Updated key", key_id
910 def DeleteKeys(self):
912 Delete any random keys we may have added.
915 for key_id in self.key_ids:
916 self.api.DeleteKey(key_id)
919 assert not self.api.GetKeys([key_id])
922 print "Deleted key", key_id
925 assert not self.api.GetKeys(self.key_ids)
929 def AddNodeGroups(self, n = 10):
931 Add a number of random node groups.
936 tag_type_id = self.nodegroup_type_ids[i]
937 tagname=self.api.GetTagTypes([tag_type_id])[0]['tagname']
940 groupname = random_nodegroup() ['groupname']
942 nodegroup_id = self.api.AddNodeGroup(groupname, tagname, value)
944 # Should return a unique nodegroup_id
945 assert nodegroup_id not in self.nodegroup_ids
946 self.nodegroup_ids.append(nodegroup_id)
950 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
951 assert nodegroup['groupname'] == groupname
952 assert nodegroup['tagname'] == tagname
953 assert nodegroup['value'] == value
956 print "Added node group", nodegroup_id
958 def UpdateNodeGroups(self):
960 Make random changes to any node groups we may have added.
963 for nodegroup_id in self.nodegroup_ids:
965 groupname = random_nodegroup()['groupname']
966 # cannot change tagname
967 nodegroup_fields = { 'groupname':groupname }
968 self.api.UpdateNodeGroup(nodegroup_id, nodegroup_fields)
972 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
973 for field in nodegroup_fields:
974 assert nodegroup[field] == nodegroup_fields[field]
977 print "Updated node group", nodegroup_id
979 def DeleteNodeGroups(self):
981 Delete any random node groups we may have added.
984 for nodegroup_id in self.nodegroup_ids:
985 self.api.DeleteNodeGroup(nodegroup_id)
988 assert not self.api.GetNodeGroups([nodegroup_id])
991 print "Deleted node group", nodegroup_id
994 assert not self.api.GetNodeGroups(self.nodegroup_ids)
996 self.nodegroup_ids = []
998 def AddNodes(self, per_site = 2):
1000 Add a number of random nodes to each site. Each node will also
1001 be added to a random node group if AddNodeGroups() was
1005 node_types = self.api.GetNodeTypes()
1007 raise Exception, "No node types"
1008 boot_states = self.api.GetBootStates()
1010 raise Exception, "No boot states"
1012 for site_id in self.site_ids:
1013 for i in range(per_site):
1015 node_fields = random_node(node_types,boot_states,self.namelengths)
1016 node_id = self.api.AddNode(site_id, node_fields)
1018 # Should return a unique node_id
1019 assert node_id not in self.node_ids
1020 self.node_ids.append(node_id)
1022 # Add to a random set of node groups
1023 nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
1024 for nodegroup_id in nodegroup_ids:
1025 tagname = self.api.GetNodeGroups([nodegroup_id])[0]['tagname']
1026 self.api.AddNodeTag( node_id, tagname, 'yes' )
1030 node = self.api.GetNodes([node_id])[0]
1031 for field in node_fields:
1032 if field not in tag_fields:
1033 assert node[field] == node_fields[field]
1036 print "Added node", node_id
1038 def UpdateNodes(self):
1040 Make random changes to any nodes we may have added.
1043 node_types = self.api.GetNodeTypes()
1045 raise Exception, "No node types"
1046 boot_states = self.api.GetBootStates()
1048 raise Exception, "No boot states"
1050 for node_id in self.node_ids:
1052 node_fields = random_node(node_types,boot_states,self.namelengths)
1053 self.api.UpdateNode(node_id, node_fields)
1055 node = self.api.GetNodes([node_id])[0]
1057 # Add to a random set of node groups
1058 nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
1059 for nodegroup_id in (set(nodegroup_ids) - set(node['nodegroup_ids'])):
1060 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
1061 tagname = nodegroup['tagname']
1062 node_tags = self.api.GetNodeTags({'node_id':node_id,'tagname':tagname})
1064 self.api.AddNodeTag(node_id,tagname,'yes')
1066 node_tag=node_tags[0]
1067 self.api.UpdateNodeTag(node_tag['node_tag_id'],'yes')
1068 for nodegroup_id in (set(node['nodegroup_ids']) - set(nodegroup_ids)):
1069 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
1070 tagname = nodegroup['tagname']
1071 node_tags = self.api.GetNodeTags({'node_id':node_id,'tagname':tagname})
1073 self.api.AddNodeTag(node_id,tagname,'no')
1075 node_tag=node_tags[0]
1076 self.api.UpdateNodeTag(node_tag['node_tag_id'],'no')
1080 node = self.api.GetNodes([node_id])[0]
1081 for field in node_fields:
1082 if field not in tag_fields:
1083 if node[field] != node_fields[field]:
1084 raise Exception, "Unexpected field %s in node after GetNodes()"%field
1085 assert set(nodegroup_ids) == set(node['nodegroup_ids'])
1087 # again but we are now fetching 'arch' explicitly
1088 node2 = self.api.GetNodes([node_id],node_fields.keys())[0]
1089 for field in node_fields:
1090 if node2[field] != node_fields[field]:
1091 raise Exception, "Unexpected field %s in node after GetNodes(tags)"%field
1094 print "Updated node", node_id
1096 def DeleteNodes(self):
1098 Delete any random nodes we may have added.
1101 for node_id in self.node_ids:
1102 # Remove from node groups
1103 node = self.api.GetNodes([node_id])[0]
1104 for node_tag in self.api.GetNodeTags ( {'node_id': node_id} ):
1105 self.api.UpdateNodeTag(node_tag['node_tag_id'],'')
1108 node = self.api.GetNodes([node_id])[0]
1109 assert not node['nodegroup_ids']
1111 self.api.DeleteNode(node_id)
1114 assert not self.api.GetNodes([node_id])
1117 print "Deleted node", node_id
1120 assert not self.api.GetNodes(self.node_ids)
1124 def AddInterfaces(self, per_node = 1):
1126 Add a number of random network interfaces to each node.
1129 network_methods = self.api.GetNetworkMethods()
1130 if not network_methods:
1131 raise Exception, "No network methods"
1133 network_types = self.api.GetNetworkTypes()
1134 if not network_types:
1135 raise Exception, "No network types"
1137 for node_id in self.node_ids:
1138 for i in range(per_node):
1139 method = random.sample(network_methods, 1)[0]
1140 type = random.sample(network_types, 1)[0]
1143 interface_fields = random_interface(method, type,self.namelengths)
1144 interface_id = self.api.AddInterface(node_id, interface_fields)
1146 # Should return a unique interface_id
1147 assert interface_id not in self.interface_ids
1148 self.interface_ids.append(interface_id)
1152 interface = self.api.GetInterfaces([interface_id])[0]
1153 for field in interface_fields:
1154 assert interface[field] == interface_fields[field]
1157 print "Added interface", interface_id, "to node", node_id
1159 def UpdateInterfaces(self):
1161 Make random changes to any network interfaces we may have added.
1164 network_methods = self.api.GetNetworkMethods()
1165 if not network_methods:
1166 raise Exception, "No network methods"
1168 network_types = self.api.GetNetworkTypes()
1169 if not network_types:
1170 raise Exception, "No network types"
1172 for interface_id in self.interface_ids:
1173 method = random.sample(network_methods, 1)[0]
1174 type = random.sample(network_types, 1)[0]
1177 interface_fields = random_interface(method, type,self.namelengths)
1178 self.api.UpdateInterface(interface_id, interface_fields)
1182 interface = self.api.GetInterfaces([interface_id])[0]
1183 for field in interface_fields:
1184 assert interface[field] == interface_fields[field]
1187 print "Updated interface", interface_id
1189 def DeleteInterfaces(self):
1191 Delete any random network interfaces we may have added.
1194 for interface_id in self.interface_ids:
1195 self.api.DeleteInterface(interface_id)
1198 assert not self.api.GetInterfaces([interface_id])
1201 print "Deleted interface", interface_id
1204 assert not self.api.GetInterfaces(self.interface_ids)
1206 self.interface_ids = []
1208 def AddIlinks (self, n):
1210 Add random links between interfaces.
1214 src = random.sample(self.interface_ids,1)[0]
1215 dst = random.sample(self.interface_ids,1)[0]
1216 ilink_id = self.api.AddIlink (src,dst,
1217 self.ilink_type_ids[i],
1220 assert ilink_id not in self.ilink_ids
1221 self.ilink_ids.append(ilink_id)
1224 print 'Added Ilink',ilink_id,' - attached interface',src,'to',dst
1227 retrieve=GetIlinks({'src_interface_id':src,'dst_interface_id':dst,
1228 'tag_type_id':self.ilink_type_ids[i]})
1229 assert ilink_id==retrieve[0]['ilink_id']
1232 def UpdateIlinks (self):
1234 for ilink_id in self.ilink_ids:
1235 new_value=random_ilink()
1236 self.api.UpdateIlink(ilink_id,new_value)
1239 ilink=self.api.GetIlinks([ilink_id])[0]
1240 assert ilink['value'] == new_value
1243 print 'Updated Ilink',ilink_id
1245 def DeleteIlinks (self):
1246 for ilink_id in self.ilink_ids:
1247 self.api.DeleteIlink(ilink_id)
1250 assert not self.api.GetIlinks({'ilink_id':ilink_id})
1253 print 'Deleted Ilink',ilink_id
1256 assert not self.api.GetIlinks(self.ilink_ids)
1261 def AddPCUs(self, per_site = 1):
1263 Add a number of random PCUs to each site. Each node at the
1264 site will be added to a port on the PCU if AddNodes() was
1268 for site_id in self.site_ids:
1269 for i in range(per_site):
1271 pcu_fields = random_pcu(self.namelengths)
1272 pcu_id = self.api.AddPCU(site_id, pcu_fields)
1274 # Should return a unique pcu_id
1275 assert pcu_id not in self.pcu_ids
1276 self.pcu_ids.append(pcu_id)
1278 # Add each node at this site to a different port on this PCU
1279 site = self.api.GetSites([site_id])[0]
1280 port = randint(1, 10)
1281 for node_id in site['node_ids']:
1282 self.api.AddNodeToPCU(node_id, pcu_id, port)
1287 pcu = self.api.GetPCUs([pcu_id])[0]
1288 for field in pcu_fields:
1289 assert pcu[field] == pcu_fields[field]
1292 print "Added PCU", pcu_id, "to site", site_id
1294 def UpdatePCUs(self):
1296 Make random changes to any PCUs we may have added.
1299 for pcu_id in self.pcu_ids:
1301 pcu_fields = random_pcu(self.namelengths)
1302 self.api.UpdatePCU(pcu_id, pcu_fields)
1306 pcu = self.api.GetPCUs([pcu_id])[0]
1307 for field in pcu_fields:
1308 assert pcu[field] == pcu_fields[field]
1311 print "Updated PCU", pcu_id
1313 def DeletePCUs(self):
1315 Delete any random nodes we may have added.
1318 for pcu_id in self.pcu_ids:
1319 # Remove nodes from PCU
1320 pcu = self.api.GetPCUs([pcu_id])[0]
1321 for node_id in pcu['node_ids']:
1322 self.api.DeleteNodeFromPCU(node_id, pcu_id)
1325 pcu = self.api.GetPCUs([pcu_id])[0]
1326 assert not pcu['node_ids']
1328 self.api.DeletePCU(pcu_id)
1331 assert not self.api.GetPCUs([pcu_id])
1334 print "Deleted PCU", pcu_id
1337 assert not self.api.GetPCUs(self.pcu_ids)
1341 def AddConfFiles(self, n = 10):
1343 Add a number of random global configuration files.
1349 # Add a random configuration file
1350 conf_files.append(random_conf_file())
1353 # Add a nodegroup override file
1354 nodegroup_conf_file = conf_files[0].copy()
1355 nodegroup_conf_file['source'] = randpath(255)
1356 conf_files.append(nodegroup_conf_file)
1358 # Add a node override file
1359 node_conf_file = conf_files[0].copy()
1360 node_conf_file['source'] = randpath(255)
1361 conf_files.append(node_conf_file)
1363 for conf_file_fields in conf_files:
1364 conf_file_id = self.api.AddConfFile(conf_file_fields)
1366 # Should return a unique conf_file_id
1367 assert conf_file_id not in self.conf_file_ids
1368 self.conf_file_ids.append(conf_file_id)
1371 if conf_file_fields == nodegroup_conf_file and self.nodegroup_ids:
1372 nodegroup_id = random.sample(self.nodegroup_ids, 1)[0]
1373 self.api.AddConfFileToNodeGroup(conf_file_id, nodegroup_id)
1378 if conf_file_fields == node_conf_file and self.node_ids:
1379 node_id = random.sample(self.node_ids, 1)[0]
1380 self.api.AddConfFileToNode(conf_file_id, node_id)
1385 # Check configuration file
1386 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1387 for field in conf_file_fields:
1388 assert conf_file[field] == conf_file_fields[field]
1391 print "Added configuration file", conf_file_id,
1392 if nodegroup_id is not None:
1393 print "to node group", nodegroup_id,
1394 elif node_id is not None:
1395 print "to node", node_id,
1398 def UpdateConfFiles(self):
1400 Make random changes to any configuration files we may have added.
1403 for conf_file_id in self.conf_file_ids:
1404 # Update configuration file
1405 conf_file_fields = random_conf_file()
1406 # Do not update dest so that it remains an override if set
1407 if 'dest' in conf_file_fields:
1408 del conf_file_fields['dest']
1409 self.api.UpdateConfFile(conf_file_id, conf_file_fields)
1412 # Check configuration file
1413 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1414 for field in conf_file_fields:
1415 assert conf_file[field] == conf_file_fields[field]
1418 print "Updated configuration file", conf_file_id
1420 def DeleteConfFiles(self):
1422 Delete any random configuration files we may have added.
1425 for conf_file_id in self.conf_file_ids:
1426 self.api.DeleteConfFile(conf_file_id)
1429 assert not self.api.GetConfFiles([conf_file_id])
1432 print "Deleted configuration file", conf_file_id
1435 assert not self.api.GetConfFiles(self.conf_file_ids)
1437 self.conf_file_ids = []
1439 def AddTagTypes(self,n_sa,n_ng,n_il):
1441 Add as many tag types as there are nodegroups,
1442 will use value=yes for each nodegroup
1445 roles = self.api.GetRoles()
1447 raise Exception, "No roles"
1448 role_ids = [role['role_id'] for role in roles]
1450 for i in range (n_sa + n_ng + n_il):
1451 tag_type_fields = random_tag_type (role_ids)
1452 tag_type_id = self.api.AddTagType (tag_type_fields)
1454 assert tag_type_id not in \
1455 self.slice_type_ids + \
1456 self.nodegroup_type_ids + \
1460 self.slice_type_ids.append(tag_type_id)
1461 elif i < n_sa+n_ng :
1462 self.nodegroup_type_ids.append(tag_type_id)
1464 self.ilink_type_ids.append(tag_type_id)
1467 tag_type = self.api.GetTagTypes([tag_type_id])[0]
1468 for field in tag_type_fields:
1469 assert tag_type[field] == tag_type_fields[field]
1471 print "Updated slice attribute type", tag_type_id
1473 def UpdateTagTypes(self):
1475 Make random changes to any slice attribute types we may have added.
1478 roles = self.api.GetRoles()
1480 raise Exception, "No roles"
1481 role_ids = [role['role_id'] for role in roles]
1483 for tag_type_id in self.slice_type_ids + self.nodegroup_type_ids + self.ilink_type_ids:
1484 # Update slice attribute type
1485 tag_type_fields = random_tag_type(role_ids)
1486 self.api.UpdateTagType(tag_type_id, tag_type_fields)
1489 # Check slice attribute type
1490 tag_type = self.api.GetTagTypes([tag_type_id])[0]
1491 for field in tag_type_fields:
1492 assert tag_type[field] == tag_type_fields[field]
1494 print "Updated slice attribute type", tag_type_id
1496 def DeleteTagTypes(self):
1498 Delete any random slice attribute types we may have added.
1501 for tag_type_id in self.slice_type_ids + self.nodegroup_type_ids + self.ilink_type_ids:
1502 self.api.DeleteTagType(tag_type_id)
1505 assert not self.api.GetTagTypes([tag_type_id])
1508 print "Deleted slice attribute type", tag_type_id
1511 assert not self.api.GetTagTypes(self.slice_type_ids+self.nodegroup_type_ids+self.ilink_type_ids)
1513 self.slice_type_ids = []
1514 self.nodegroup_type_ids = []
1516 def AddSlices(self, per_site = 10):
1518 Add a number of random slices per site.
1521 for site in self.api.GetSites(self.site_ids):
1522 for i in range(min(per_site, site['max_slices'])):
1524 slice_fields = random_slice(site['login_base'],self.namelengths)
1525 slice_id = self.api.AddSlice(slice_fields)
1527 # Should return a unique slice_id
1528 assert slice_id not in self.slice_ids
1529 self.slice_ids.append(slice_id)
1531 # Add slice to a random set of nodes
1532 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1534 self.api.AddSliceToNodes(slice_id, node_ids)
1536 # Add random set of site users to slice
1537 person_ids = random.sample(site['person_ids'], randint(0, len(site['person_ids'])))
1538 for person_id in person_ids:
1539 self.api.AddPersonToSlice(person_id, slice_id)
1543 slice = self.api.GetSlices([slice_id])[0]
1544 for field in slice_fields:
1545 assert slice[field] == slice_fields[field]
1547 assert set(node_ids) == set(slice['node_ids'])
1548 assert set(person_ids) == set(slice['person_ids'])
1551 print "Added slice", slice_id, "to site", site['site_id'],
1553 print "and nodes", node_ids,
1556 print "Added users", site['person_ids'], "to slice", slice_id
1558 def UpdateSlices(self):
1560 Make random changes to any slices we may have added.
1563 for slice_id in self.slice_ids:
1565 slice_fields = random_slice("unused",self.namelengths)
1566 # Cannot change slice name
1567 if 'name' in slice_fields:
1568 del slice_fields['name']
1569 self.api.UpdateSlice(slice_id, slice_fields)
1571 slice = self.api.GetSlices([slice_id])[0]
1573 # Add slice to a random set of nodes
1574 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1575 self.api.AddSliceToNodes(slice_id, list(set(node_ids) - set(slice['node_ids'])))
1576 self.api.DeleteSliceFromNodes(slice_id, list(set(slice['node_ids']) - set(node_ids)))
1578 # Add random set of users to slice
1579 person_ids = random.sample(self.person_ids, randint(0, len(self.person_ids)))
1580 for person_id in (set(person_ids) - set(slice['person_ids'])):
1581 self.api.AddPersonToSlice(person_id, slice_id)
1582 for person_id in (set(slice['person_ids']) - set(person_ids)):
1583 self.api.DeletePersonFromSlice(person_id, slice_id)
1586 slice = self.api.GetSlices([slice_id])[0]
1587 for field in slice_fields:
1588 assert slice[field] == slice_fields[field]
1589 assert set(node_ids) == set(slice['node_ids'])
1590 assert set(person_ids) == set(slice['person_ids'])
1593 print "Updated slice", slice_id
1594 print "Added nodes", node_ids, "to slice", slice_id
1595 print "Added persons", person_ids, "to slice", slice_id
1597 def DeleteSlices(self):
1599 Delete any random slices we may have added.
1602 for slice_id in self.slice_ids:
1603 self.api.DeleteSlice(slice_id)
1606 assert not self.api.GetSlices([slice_id])
1609 print "Deleted slice", slice_id
1612 assert not self.api.GetSlices(self.slice_ids)
1616 def AddSliceTags(self, per_slice = 2):
1618 Add a number of random slices per site.
1621 if not self.slice_type_ids:
1624 for slice_id in self.slice_ids:
1625 slice = self.api.GetSlices([slice_id])[0]
1627 for i in range(per_slice):
1628 # Set a random slice/sliver attribute
1629 for tag_type_id in random.sample(self.slice_type_ids, 1):
1630 value = randstr(16, letters + '_' + digits)
1631 # Make it a sliver attribute with 50% probability
1632 if slice['node_ids']:
1633 node_id = random.sample(slice['node_ids'] + [None] * len(slice['node_ids']), 1)[0]
1637 # Add slice attribute
1639 slice_tag_id = self.api.AddSliceTag(slice_id, tag_type_id, value)
1641 slice_tag_id = self.api.AddSliceTag(slice_id, tag_type_id, value, node_id)
1643 # Should return a unique slice_tag_id
1644 assert slice_tag_id not in self.slice_tag_ids
1645 self.slice_tag_ids.append(slice_tag_id)
1648 # Check slice attribute
1649 slice_tag = self.api.GetSliceTags([slice_tag_id])[0]
1650 for field in 'tag_type_id', 'slice_id', 'node_id', 'slice_tag_id', 'value':
1651 assert slice_tag[field] == locals()[field]
1654 print "Added slice attribute", slice_tag_id, "of type", tag_type_id,
1655 if node_id is not None:
1656 print "to node", node_id,
1659 def UpdateSliceTags(self):
1661 Make random changes to any slice attributes we may have added.
1664 for slice_tag_id in self.slice_tag_ids:
1665 # Update slice attribute
1666 value = randstr(16, letters + '_' + digits)
1667 self.api.UpdateSliceTag(slice_tag_id, value)
1669 # Check slice attribute again
1670 slice_tag = self.api.GetSliceTags([slice_tag_id])[0]
1671 assert slice_tag['value'] == value
1674 print "Updated slice attribute", slice_tag_id
1676 def DeleteSliceTags(self):
1678 Delete any random slice attributes we may have added.
1681 for slice_tag_id in self.slice_tag_ids:
1682 self.api.DeleteSliceTag(slice_tag_id)
1685 assert not self.api.GetSliceTags([slice_tag_id])
1688 print "Deleted slice attribute", slice_tag_id
1691 assert not self.api.GetSliceTags(self.slice_tag_ids)
1693 self.slice_tag_ids = []
1696 parser = OptionParser()
1697 parser.add_option("-c", "--check", action = "store_true", default = False,
1698 help = "Check most actions (default: %default)")
1699 parser.add_option("-q", "--quiet", action = "store_true", default = False,
1700 help = "Be quiet (default: %default)")
1701 parser.add_option("-p","--preserve", action="store_true", default =False,
1702 help = "Do not delete created objects")
1703 parser.add_option("-t", "--tiny", action = "store_true", default = False,
1704 help = "Run a tiny test (default: %default)")
1705 parser.add_option("-l", "--large", action = "store_true", default = False,
1706 help = "Run a large test (default: %default)")
1707 parser.add_option("-x", "--xlarge", action = "store_true", default = False,
1708 help = "Run an XL test (default: %default)")
1709 parser.add_option("-s", "--short-names", action="store_true", dest="short_names", default = False,
1710 help = "Generate smaller names for checking UI rendering")
1711 parser.add_option ("-f", "--foreign", action="store_true", dest="federating", default = False,
1712 help = "Create a fake peer and add items in it (no update, no delete)")
1713 (options, args) = parser.parse_args()
1715 test = Test(api = Shell(),
1716 check = options.check,
1717 verbose = not options.quiet,
1718 preserve = options.preserve,
1719 federating = options.federating)
1721 if options.short_names:
1722 test.namelengths = Test.namelengths_short
1724 test.namelengths = Test.namelengths_default
1727 sizes = Test.sizes_tiny
1729 sizes = Test.sizes_large
1730 elif options.xlarge:
1731 sizes = Test.sizes_xlarge
1733 sizes = Test.sizes_default
1737 if __name__ == "__main__":