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 print 'WARNING: skipping updatenode with tags as this is not implemented yet'
1088 # again when fetching 'arch' explicitly
1089 node2 = self.api.GetNodes([node_id],node_fields.keys())[0]
1090 for field in node_fields:
1091 if node2[field] != node_fields[field]:
1092 raise Exception, "Unexpected field %s in node after GetNodes(tags)"%field
1095 print "Updated node", node_id
1097 def DeleteNodes(self):
1099 Delete any random nodes we may have added.
1102 for node_id in self.node_ids:
1103 # Remove from node groups
1104 node = self.api.GetNodes([node_id])[0]
1105 for node_tag in GetNodeTags ( {'node_id': node_id} ):
1106 self.api.UpdateNodeTag(node_tag['node_tag_id'],'')
1109 node = self.api.GetNodes([node_id])[0]
1110 assert not node['nodegroup_ids']
1112 self.api.DeleteNode(node_id)
1115 assert not self.api.GetNodes([node_id])
1118 print "Deleted node", node_id
1121 assert not self.api.GetNodes(self.node_ids)
1125 def AddInterfaces(self, per_node = 1):
1127 Add a number of random network interfaces to each node.
1130 network_methods = self.api.GetNetworkMethods()
1131 if not network_methods:
1132 raise Exception, "No network methods"
1134 network_types = self.api.GetNetworkTypes()
1135 if not network_types:
1136 raise Exception, "No network types"
1138 for node_id in self.node_ids:
1139 for i in range(per_node):
1140 method = random.sample(network_methods, 1)[0]
1141 type = random.sample(network_types, 1)[0]
1144 interface_fields = random_interface(method, type,self.namelengths)
1145 interface_id = self.api.AddInterface(node_id, interface_fields)
1147 # Should return a unique interface_id
1148 assert interface_id not in self.interface_ids
1149 self.interface_ids.append(interface_id)
1153 interface = self.api.GetInterfaces([interface_id])[0]
1154 for field in interface_fields:
1155 assert interface[field] == interface_fields[field]
1158 print "Added interface", interface_id, "to node", node_id
1160 def UpdateInterfaces(self):
1162 Make random changes to any network interfaces we may have added.
1165 network_methods = self.api.GetNetworkMethods()
1166 if not network_methods:
1167 raise Exception, "No network methods"
1169 network_types = self.api.GetNetworkTypes()
1170 if not network_types:
1171 raise Exception, "No network types"
1173 for interface_id in self.interface_ids:
1174 method = random.sample(network_methods, 1)[0]
1175 type = random.sample(network_types, 1)[0]
1178 interface_fields = random_interface(method, type)
1179 self.api.UpdateInterface(interface_id, interface_fields)
1183 interface = self.api.GetInterfaces([interface_id])[0]
1184 for field in interface_fields:
1185 assert interface[field] == interface_fields[field]
1188 print "Updated interface", interface_id
1190 def DeleteInterfaces(self):
1192 Delete any random network interfaces we may have added.
1195 for interface_id in self.interface_ids:
1196 self.api.DeleteInterface(interface_id)
1199 assert not self.api.GetInterfaces([interface_id])
1202 print "Deleted interface", interface_id
1205 assert not self.api.GetInterfaces(self.interface_ids)
1207 self.interface_ids = []
1209 def AddIlinks (self, n):
1211 Add random links between interfaces.
1215 src = random.sample(self.interface_ids,1)[0]
1216 dst = random.sample(self.interface_ids,1)[0]
1217 ilink_id = self.api.AddIlink (src,dst,
1218 self.ilink_type_ids[i],
1221 assert ilink_id not in self.ilink_ids
1222 self.ilink_ids.append(ilink_id)
1225 print 'Added Ilink',ilink_id,' - attached interface',src,'to',dst
1228 retrieve=GetIlinks({'src_interface_id':src,'dst_interface_id':dst,
1229 'tag_type_id':self.ilink_type_ids[i]})
1230 assert ilink_id==retrieve[0]['ilink_id']
1233 def UpdateIlinks (self):
1235 for ilink_id in self.ilink_ids:
1236 new_value=random_ilink()
1237 self.api.UpdateIlink(ilink_id,new_value)
1240 ilink=self.api.GetIlinks([ilink_id])[0]
1241 assert ilink['value'] == new_value
1244 print 'Updated Ilink',ilink_id
1246 def DeleteIlinks (self):
1247 for ilink_id in self.ilink_ids:
1248 self.api.DeleteIlink(ilink_id)
1251 assert not self.api.GetIlinks({'ilink_id':ilink_id})
1254 print 'Deleted Ilink',ilink_id
1257 assert not self.api.GetIlinks(self.ilink_ids)
1262 def AddPCUs(self, per_site = 1):
1264 Add a number of random PCUs to each site. Each node at the
1265 site will be added to a port on the PCU if AddNodes() was
1269 for site_id in self.site_ids:
1270 for i in range(per_site):
1272 pcu_fields = random_pcu(self.namelengths)
1273 pcu_id = self.api.AddPCU(site_id, pcu_fields)
1275 # Should return a unique pcu_id
1276 assert pcu_id not in self.pcu_ids
1277 self.pcu_ids.append(pcu_id)
1279 # Add each node at this site to a different port on this PCU
1280 site = self.api.GetSites([site_id])[0]
1281 port = randint(1, 10)
1282 for node_id in site['node_ids']:
1283 self.api.AddNodeToPCU(node_id, pcu_id, port)
1288 pcu = self.api.GetPCUs([pcu_id])[0]
1289 for field in pcu_fields:
1290 assert pcu[field] == pcu_fields[field]
1293 print "Added PCU", pcu_id, "to site", site_id
1295 def UpdatePCUs(self):
1297 Make random changes to any PCUs we may have added.
1300 for pcu_id in self.pcu_ids:
1302 pcu_fields = random_pcu(self.namelengths)
1303 self.api.UpdatePCU(pcu_id, pcu_fields)
1307 pcu = self.api.GetPCUs([pcu_id])[0]
1308 for field in pcu_fields:
1309 assert pcu[field] == pcu_fields[field]
1312 print "Updated PCU", pcu_id
1314 def DeletePCUs(self):
1316 Delete any random nodes we may have added.
1319 for pcu_id in self.pcu_ids:
1320 # Remove nodes from PCU
1321 pcu = self.api.GetPCUs([pcu_id])[0]
1322 for node_id in pcu['node_ids']:
1323 self.api.DeleteNodeFromPCU(node_id, pcu_id)
1326 pcu = self.api.GetPCUs([pcu_id])[0]
1327 assert not pcu['node_ids']
1329 self.api.DeletePCU(pcu_id)
1332 assert not self.api.GetPCUs([pcu_id])
1335 print "Deleted PCU", pcu_id
1338 assert not self.api.GetPCUs(self.pcu_ids)
1342 def AddConfFiles(self, n = 10):
1344 Add a number of random global configuration files.
1350 # Add a random configuration file
1351 conf_files.append(random_conf_file())
1354 # Add a nodegroup override file
1355 nodegroup_conf_file = conf_files[0].copy()
1356 nodegroup_conf_file['source'] = randpath(255)
1357 conf_files.append(nodegroup_conf_file)
1359 # Add a node override file
1360 node_conf_file = conf_files[0].copy()
1361 node_conf_file['source'] = randpath(255)
1362 conf_files.append(node_conf_file)
1364 for conf_file_fields in conf_files:
1365 conf_file_id = self.api.AddConfFile(conf_file_fields)
1367 # Should return a unique conf_file_id
1368 assert conf_file_id not in self.conf_file_ids
1369 self.conf_file_ids.append(conf_file_id)
1372 if conf_file_fields == nodegroup_conf_file and self.nodegroup_ids:
1373 nodegroup_id = random.sample(self.nodegroup_ids, 1)[0]
1374 self.api.AddConfFileToNodeGroup(conf_file_id, nodegroup_id)
1379 if conf_file_fields == node_conf_file and self.node_ids:
1380 node_id = random.sample(self.node_ids, 1)[0]
1381 self.api.AddConfFileToNode(conf_file_id, node_id)
1386 # Check configuration file
1387 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1388 for field in conf_file_fields:
1389 assert conf_file[field] == conf_file_fields[field]
1392 print "Added configuration file", conf_file_id,
1393 if nodegroup_id is not None:
1394 print "to node group", nodegroup_id,
1395 elif node_id is not None:
1396 print "to node", node_id,
1399 def UpdateConfFiles(self):
1401 Make random changes to any configuration files we may have added.
1404 for conf_file_id in self.conf_file_ids:
1405 # Update configuration file
1406 conf_file_fields = random_conf_file()
1407 # Do not update dest so that it remains an override if set
1408 if 'dest' in conf_file_fields:
1409 del conf_file_fields['dest']
1410 self.api.UpdateConfFile(conf_file_id, conf_file_fields)
1413 # Check configuration file
1414 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1415 for field in conf_file_fields:
1416 assert conf_file[field] == conf_file_fields[field]
1419 print "Updated configuration file", conf_file_id
1421 def DeleteConfFiles(self):
1423 Delete any random configuration files we may have added.
1426 for conf_file_id in self.conf_file_ids:
1427 self.api.DeleteConfFile(conf_file_id)
1430 assert not self.api.GetConfFiles([conf_file_id])
1433 print "Deleted configuration file", conf_file_id
1436 assert not self.api.GetConfFiles(self.conf_file_ids)
1438 self.conf_file_ids = []
1440 def AddTagTypes(self,n_sa,n_ng,n_il):
1442 Add as many tag types as there are nodegroups,
1443 will use value=yes for each nodegroup
1446 roles = self.api.GetRoles()
1448 raise Exception, "No roles"
1449 role_ids = [role['role_id'] for role in roles]
1451 for i in range (n_sa + n_ng + n_il):
1452 tag_type_fields = random_tag_type (role_ids)
1453 tag_type_id = self.api.AddTagType (tag_type_fields)
1455 assert tag_type_id not in \
1456 self.slice_type_ids + \
1457 self.nodegroup_type_ids + \
1461 self.slice_type_ids.append(tag_type_id)
1462 elif i < n_sa+n_ng :
1463 self.nodegroup_type_ids.append(tag_type_id)
1465 self.ilink_type_ids.append(tag_type_id)
1468 tag_type = self.api.GetTagTypes([tag_type_id])[0]
1469 for field in tag_type_fields:
1470 assert tag_type[field] == tag_type_fields[field]
1472 print "Updated slice attribute type", tag_type_id
1474 def UpdateTagTypes(self):
1476 Make random changes to any slice attribute types we may have added.
1479 roles = self.api.GetRoles()
1481 raise Exception, "No roles"
1482 role_ids = [role['role_id'] for role in roles]
1484 for tag_type_id in self.slice_type_ids + self.nodegroup_type_ids + self.ilink_type_ids:
1485 # Update slice attribute type
1486 tag_type_fields = random_tag_type(role_ids)
1487 self.api.UpdateTagType(tag_type_id, tag_type_fields)
1490 # Check slice attribute type
1491 tag_type = self.api.GetTagTypes([tag_type_id])[0]
1492 for field in tag_type_fields:
1493 assert tag_type[field] == tag_type_fields[field]
1495 print "Updated slice attribute type", tag_type_id
1497 def DeleteTagTypes(self):
1499 Delete any random slice attribute types we may have added.
1502 for tag_type_id in self.slice_type_ids + self.nodegroup_type_ids + self.ilink_type_ids:
1503 self.api.DeleteTagType(tag_type_id)
1506 assert not self.api.GetTagTypes([tag_type_id])
1509 print "Deleted slice attribute type", tag_type_id
1512 assert not self.api.GetTagTypes(self.slice_type_ids+self.nodegroup_type_ids+self.ilink_type_ids)
1514 self.slice_type_ids = []
1515 self.nodegroup_type_ids = []
1517 def AddSlices(self, per_site = 10):
1519 Add a number of random slices per site.
1522 for site in self.api.GetSites(self.site_ids):
1523 for i in range(min(per_site, site['max_slices'])):
1525 slice_fields = random_slice(site['login_base'],self.namelengths)
1526 slice_id = self.api.AddSlice(slice_fields)
1528 # Should return a unique slice_id
1529 assert slice_id not in self.slice_ids
1530 self.slice_ids.append(slice_id)
1532 # Add slice to a random set of nodes
1533 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1535 self.api.AddSliceToNodes(slice_id, node_ids)
1537 # Add random set of site users to slice
1538 person_ids = random.sample(site['person_ids'], randint(0, len(site['person_ids'])))
1539 for person_id in person_ids:
1540 self.api.AddPersonToSlice(person_id, slice_id)
1544 slice = self.api.GetSlices([slice_id])[0]
1545 for field in slice_fields:
1546 assert slice[field] == slice_fields[field]
1548 assert set(node_ids) == set(slice['node_ids'])
1549 assert set(person_ids) == set(slice['person_ids'])
1552 print "Added slice", slice_id, "to site", site['site_id'],
1554 print "and nodes", node_ids,
1557 print "Added users", site['person_ids'], "to slice", slice_id
1559 def UpdateSlices(self):
1561 Make random changes to any slices we may have added.
1564 for slice_id in self.slice_ids:
1566 slice_fields = random_slice("unused",self.namelengths)
1567 # Cannot change slice name
1568 if 'name' in slice_fields:
1569 del slice_fields['name']
1570 self.api.UpdateSlice(slice_id, slice_fields)
1572 slice = self.api.GetSlices([slice_id])[0]
1574 # Add slice to a random set of nodes
1575 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1576 self.api.AddSliceToNodes(slice_id, list(set(node_ids) - set(slice['node_ids'])))
1577 self.api.DeleteSliceFromNodes(slice_id, list(set(slice['node_ids']) - set(node_ids)))
1579 # Add random set of users to slice
1580 person_ids = random.sample(self.person_ids, randint(0, len(self.person_ids)))
1581 for person_id in (set(person_ids) - set(slice['person_ids'])):
1582 self.api.AddPersonToSlice(person_id, slice_id)
1583 for person_id in (set(slice['person_ids']) - set(person_ids)):
1584 self.api.DeletePersonFromSlice(person_id, slice_id)
1587 slice = self.api.GetSlices([slice_id])[0]
1588 for field in slice_fields:
1589 assert slice[field] == slice_fields[field]
1590 assert set(node_ids) == set(slice['node_ids'])
1591 assert set(person_ids) == set(slice['person_ids'])
1594 print "Updated slice", slice_id
1595 print "Added nodes", node_ids, "to slice", slice_id
1596 print "Added persons", person_ids, "to slice", slice_id
1598 def DeleteSlices(self):
1600 Delete any random slices we may have added.
1603 for slice_id in self.slice_ids:
1604 self.api.DeleteSlice(slice_id)
1607 assert not self.api.GetSlices([slice_id])
1610 print "Deleted slice", slice_id
1613 assert not self.api.GetSlices(self.slice_ids)
1617 def AddSliceTags(self, per_slice = 2):
1619 Add a number of random slices per site.
1622 if not self.slice_type_ids:
1625 for slice_id in self.slice_ids:
1626 slice = self.api.GetSlices([slice_id])[0]
1628 for i in range(per_slice):
1629 # Set a random slice/sliver attribute
1630 for tag_type_id in random.sample(self.slice_type_ids, 1):
1631 value = randstr(16, letters + '_' + digits)
1632 # Make it a sliver attribute with 50% probability
1633 if slice['node_ids']:
1634 node_id = random.sample(slice['node_ids'] + [None] * len(slice['node_ids']), 1)[0]
1638 # Add slice attribute
1640 slice_tag_id = self.api.AddSliceTag(slice_id, tag_type_id, value)
1642 slice_tag_id = self.api.AddSliceTag(slice_id, tag_type_id, value, node_id)
1644 # Should return a unique slice_tag_id
1645 assert slice_tag_id not in self.slice_tag_ids
1646 self.slice_tag_ids.append(slice_tag_id)
1649 # Check slice attribute
1650 slice_tag = self.api.GetSliceTags([slice_tag_id])[0]
1651 for field in 'tag_type_id', 'slice_id', 'node_id', 'slice_tag_id', 'value':
1652 assert slice_tag[field] == locals()[field]
1655 print "Added slice attribute", slice_tag_id, "of type", tag_type_id,
1656 if node_id is not None:
1657 print "to node", node_id,
1660 def UpdateSliceTags(self):
1662 Make random changes to any slice attributes we may have added.
1665 for slice_tag_id in self.slice_tag_ids:
1666 # Update slice attribute
1667 value = randstr(16, letters + '_' + digits)
1668 self.api.UpdateSliceTag(slice_tag_id, value)
1670 # Check slice attribute again
1671 slice_tag = self.api.GetSliceTags([slice_tag_id])[0]
1672 assert slice_tag['value'] == value
1675 print "Updated slice attribute", slice_tag_id
1677 def DeleteSliceTags(self):
1679 Delete any random slice attributes we may have added.
1682 for slice_tag_id in self.slice_tag_ids:
1683 self.api.DeleteSliceTag(slice_tag_id)
1686 assert not self.api.GetSliceTags([slice_tag_id])
1689 print "Deleted slice attribute", slice_tag_id
1692 assert not self.api.GetSliceTags(self.slice_tag_ids)
1694 self.slice_tag_ids = []
1697 parser = OptionParser()
1698 parser.add_option("-c", "--check", action = "store_true", default = False,
1699 help = "Check most actions (default: %default)")
1700 parser.add_option("-q", "--quiet", action = "store_true", default = False,
1701 help = "Be quiet (default: %default)")
1702 parser.add_option("-p","--preserve", action="store_true", default =False,
1703 help = "Do not delete created objects")
1704 parser.add_option("-t", "--tiny", action = "store_true", default = False,
1705 help = "Run a tiny test (default: %default)")
1706 parser.add_option("-l", "--large", action = "store_true", default = False,
1707 help = "Run a large test (default: %default)")
1708 parser.add_option("-x", "--xlarge", action = "store_true", default = False,
1709 help = "Run an XL test (default: %default)")
1710 parser.add_option("-s", "--short-names", action="store_true", dest="short_names", default = False,
1711 help = "Generate smaller names for checking UI rendering")
1712 parser.add_option ("-f", "--foreign", action="store_true", dest="federating", default = False,
1713 help = "Create a fake peer and add items in it (no update, no delete)")
1714 (options, args) = parser.parse_args()
1716 test = Test(api = Shell(),
1717 check = options.check,
1718 verbose = not options.quiet,
1719 preserve = options.preserve,
1720 federating = options.federating)
1722 if options.short_names:
1723 test.namelengths = Test.namelengths_short
1725 test.namelengths = Test.namelengths_default
1728 sizes = Test.sizes_tiny
1730 sizes = Test.sizes_large
1731 elif options.xlarge:
1732 sizes = Test.sizes_xlarge
1734 sizes = Test.sizes_default
1738 if __name__ == "__main__":