3 # WARNING: as opposed to the rest of the python code in this repo
4 # the current script runs on top of plcsh and so it is for now
5 # pinned as python2 code
8 # Test script utility class
10 # Mark Huang <mlhuang@cs.princeton.edu>
11 # Copyright (C) 2006 The Trustees of Princeton University
14 # NOTE on porting to python3
16 # this file gets fed to plcsh on the tested myplc, so
17 # it needs to remain python2 for now
20 from pprint import pprint
21 from string import letters, digits, punctuation, whitespace
22 from traceback import print_exc
23 from optparse import OptionParser
30 from PLC.Shell import Shell
32 from random import Random
35 # note about namelengths
36 # original version uses full lengths for all fields for testing overflows and things
37 # however for a realistic test, involving a web UI, this is not appropriate, so we
38 # use smaller identifiers
40 def randfloat(min = 0.0, max = 1.0):
41 return float(min) + (random.random() * (float(max) - float(min)))
43 def randint(min = 0, max = 1):
44 return int(randfloat(min, max + 1))
46 # See "2.2 Characters" in the XML specification:
48 # #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
50 # [#x7F-#x84], [#x86-#x9F], [#xFDD0-#xFDDF]
53 ascii_xml_chars = list(map(chr, [0x9, 0xA]))
54 # xmlrpclib uses xml.parsers.expat, which always converts either '\r'
55 # (#xD) or '\n' (#xA) to '\n'. So avoid using '\r', too, if this is
57 if xmlrpc.client.loads(xmlrpc.client.dumps(('\r',)))[0][0] == '\r':
58 ascii_xml_chars.append('\r')
59 ascii_xml_chars += list(map(chr, range(0x20, 0x7F - 1)))
60 low_xml_chars = list(ascii_xml_chars)
61 low_xml_chars += list(map(chr, range(0x84 + 1, 0x86 - 1)))
62 low_xml_chars += list(map(chr, range(0x9F + 1, 0xFF)))
63 valid_xml_chars = list(low_xml_chars)
64 valid_xml_chars += list(map(chr, range(0xFF + 1, 0xD7FF)))
65 valid_xml_chars += list(map(chr, range(0xE000, 0xFDD0 - 1)))
66 valid_xml_chars += list(map(chr, range(0xFDDF + 1, 0xFFFD)))
68 def randstr(length, pool = valid_xml_chars, encoding = "utf-8"):
69 sample = random.sample(pool, min(length, len(pool)))
72 bytes = len(s.encode(encoding))
76 sample += random.sample(pool, min(length - bytes, len(pool)))
77 random.shuffle(sample)
82 def randhostname(namelengths):
83 # 1. Each part begins and ends with a letter or number.
84 # 2. Each part except the last can contain letters, numbers, or hyphens.
85 # 3. Each part is between 1 and 64 characters, including the trailing dot.
86 # 4. At least two parts.
87 # 5. Last part can only contain between 2 and 6 letters.
88 hostname = 'a' + randstr(namelengths['hostname1'], letters + digits + '-') + '1.' + \
89 'b' + randstr(namelengths['hostname1'], letters + digits + '-') + '2.' + \
90 'c' + randstr(namelengths['hostname2'], letters)
91 return hostname.lower()
95 for i in range(randint(1, 10)):
96 parts.append(randstr(randint(1, 30), ascii_xml_chars))
97 return '/'.join(parts)[0:length]
99 def randemail(namelengths):
100 return (randstr(namelengths['email'], letters + digits) + "@" + randhostname(namelengths)).lower()
102 def randkey(namelengths,bits = 2048):
103 ssh_key_types = ["ssh-dss", "ssh-rsa"]
104 key_type = random.sample(ssh_key_types, 1)[0]
105 return ' '.join([key_type,
106 base64.b64encode(''.join(randstr(bits / 8).encode("utf-8"))),
107 randemail(namelengths)])
111 'peername': randstr(24,letters + ' ' + digits),
112 'peer_url': "https://" + randhostname ({'hostname1':8,'hostname2':3}) + ":443/PLCAPI/",
113 'key' : randstr(1024,letters+digits),
114 'cacert' : randstr(1024,letters+digits),
115 'shortname' : randstr(1,letters) + 'LAB',
116 'hrn_root' : 'planetlab.' + randstr (3,letters),
119 def random_site(namelengths):
120 sitename=randstr(namelengths['sitename'],namelengths['sitename_contents'])
121 abbreviated_name=randstr(namelengths['abbreviated_name'],namelengths['abbreviated_name_contents'])
123 print('nl[a] in random_site',namelengths['abbreviated_name'],'actual',len(abbreviated_name))
126 'abbreviated_name': abbreviated_name,
127 'login_base': randstr(namelengths['login_base'], letters).lower(),
128 'latitude': int(randfloat(-90.0, 90.0) * 1000) / 1000.0,
129 'longitude': int(randfloat(-180.0, 180.0) * 1000) / 1000.0,
132 def random_address_type():
135 'description': randstr(254),
138 def random_address():
140 'line1': randstr(254),
141 'line2': randstr(254),
142 'line3': randstr(254),
143 'city': randstr(254),
144 'state': randstr(254),
145 'postalcode': randstr(64),
146 'country': randstr(128),
149 def random_person(namelengths):
151 'first_name': randstr(namelengths['first_name']),
152 'last_name': randstr(namelengths['last_name']),
153 'email': randemail(namelengths),
155 # Accounts are disabled by default
157 'password': randstr(254),
160 def random_key(key_types,namelengths):
162 'key_type': random.sample(key_types, 1)[0],
163 'key': randkey(namelengths)
166 def random_tag_type (role_ids):
167 return {'tagname': randstr(12,letters+digits),
168 'category':randstr(4,letters+digits)+'/'+randstr(6,letters+digits),
169 'description' : randstr(128,letters+digits+whitespace+punctuation),
172 def random_nodegroup():
173 return {'groupname' : randstr(30, letters+digits+whitespace) }
175 def random_roles(role_ids):
176 nb_roles=len(role_ids)
177 return random.sample(role_ids,random.choice(list(range(1,nb_roles+1))))
180 def random_node(node_types,boot_states,namelengths):
182 'hostname': randhostname(namelengths),
183 'node_type': random.sample(node_types,1)[0],
184 'boot_state': random.sample(boot_states, 1)[0],
185 'model': randstr(namelengths['model']),
186 'version': randstr(64),
187 # for testing node tags
191 def random_interface(method, type,namelengths):
195 'bwlimit': randint(500000, 10000000),
199 ip = randint(0, 0xffffffff)
200 netmask = (0xffffffff << randint(2, 31)) & 0xffffffff
201 network = ip & netmask
202 broadcast = ((ip & netmask) | ~netmask) & 0xffffffff
203 gateway = randint(network + 1, broadcast - 1)
204 dns1 = randint(0, 0xffffffff)
206 for field in 'ip', 'netmask', 'network', 'broadcast', 'gateway', 'dns1':
207 interface_fields[field] = socket.inet_ntoa(struct.pack('>L', locals()[field]))
209 interface_fields['hostname']=randhostname(namelengths);
211 return interface_fields
216 def random_pcu(namelengths):
218 'hostname': randhostname(namelengths),
219 'ip': socket.inet_ntoa(struct.pack('>L', randint(0, 0xffffffff))),
220 'protocol': randstr(16),
221 'username': randstr(254),
222 'password': randstr(254),
223 'notes': randstr(254),
224 'model': randstr(32),
227 def random_conf_file():
229 'enabled': bool(randint()),
230 'source': randpath(255),
231 'dest': randpath(255),
232 'file_permissions': "%#o" % randint(0, 512),
233 'file_owner': randstr(32, letters + '_' + digits),
234 'file_group': randstr(32, letters + '_' + digits),
235 'preinstall_cmd': randpath(100),
236 'postinstall_cmd': randpath(100),
237 'error_cmd': randpath(100),
238 'ignore_cmd_errors': bool(randint()),
239 'always_update': bool(randint()),
242 def random_slice(login_base,namelengths):
244 'name': login_base + "_" + randstr(11, letters).lower(),
245 'url': "http://" + randhostname(namelengths) + "/",
246 'description': randstr(2048),
253 'addresses_per_site': 1,
254 'persons_per_site': 1,
255 'keys_per_person': 1,
259 'interfaces_per_node': 1,
263 'slices_per_site': 1,
264 'attributes_per_slice': 1,
270 'addresses_per_site': 2,
271 'persons_per_site': 4,
272 'keys_per_person': 2,
276 'interfaces_per_node': 1,
280 'slices_per_site': 4,
281 'attributes_per_slice': 2,
287 'addresses_per_site': 2,
288 'persons_per_site': 5,
289 'keys_per_person': 2,
293 'interfaces_per_node': 2,
297 'slices_per_site': 10,
298 'attributes_per_slice': 4,
304 'addresses_per_site': 2,
305 'persons_per_site': 5,
306 'keys_per_person': 2,
310 'interfaces_per_node': 2,
314 'slices_per_site': 10,
315 'attributes_per_slice': 4,
318 namelengths_default = {
323 'sitename_contents':letters+digits,
324 'abbreviated_name':50,
325 'abbreviated_name_contents':letters+digits+whitespace+punctuation,
332 namelengths_short = {
337 'sitename_contents':letters+digits,
338 'abbreviated_name':24,
339 'abbreviated_name_contents':letters+digits+whitespace+punctuation,
346 def __init__(self, api, check, verbose, preserve, federating):
349 self.verbose = verbose
350 self.preserve = preserve
351 self.federating = federating
354 self.address_type_ids = []
355 self.address_ids = []
358 self.slice_type_ids = []
359 self.nodegroup_type_ids = []
360 self.ilink_type_ids = []
361 self.nodegroup_ids = []
363 self.interface_ids = []
366 self.conf_file_ids = []
368 self.slice_tag_ids = []
370 def Cardinals (self):
371 return [len(x) for x in (
372 self.api.GetNodes({},['node_id']),
373 self.api.GetSites({},['site_id']),
374 self.api.GetPersons({},['person_id']),
375 self.api.GetSlices({},['slice_id']),
378 def Run(self, **kwds):
380 Run a complete database and API consistency test. Populates
381 the database with a set of random entities, updates them, then
382 deletes them. Examples:
384 test.Run() # Defaults
385 test.Run(**Test.sizes_default) # Defaults
386 test.Run(**Test.sizes_tiny) # Tiny set
387 test.Run(sites = 123, slices_per_site = 4) # Defaults with overrides
390 cardinals_before=self.Cardinals()
391 print('Cardinals before test (n,s,p,sl)',cardinals_before)
394 # if federating : we're done
396 if self.federating or self.preserve:
397 print('Preserving - update & delete skipped')
402 cardinals_after=self.Cardinals()
403 print('Cardinals after test (n,s,p,sl)',cardinals_after)
405 if cardinals_before != cardinals_after:
406 raise Exception('cardinals before and after differ - check deletion mechanisms')
408 def Add(self, **kwds):
410 Populate the database with a set of random entities. Examples:
415 sizes = self.sizes_default.copy()
418 if not self.federating:
419 self.AddSites(sizes['sites'])
420 self.AddAddressTypes(sizes['address_types'])
421 self.AddAddresses(sizes['addresses_per_site'])
422 self.AddPersons(sizes['persons_per_site'])
423 self.AddKeys(sizes['keys_per_person'])
424 self.AddTagTypes(sizes['slice_tags'],sizes['nodegroups'],sizes['ilinks'])
425 self.AddNodeGroups(sizes['nodegroups'])
426 self.AddNodes(sizes['nodes_per_site'])
427 self.AddInterfaces(sizes['interfaces_per_node'])
428 self.AddIlinks (sizes['ilinks'])
429 self.AddPCUs(sizes['pcus_per_site'])
430 self.AddConfFiles(sizes['conf_files'])
431 self.AddSlices(sizes['slices_per_site'])
432 self.AddSliceTags(sizes['attributes_per_slice'])
436 self.AddSites(sizes['sites'])
437 self.AddPersons(sizes['persons_per_site'])
438 self.AddKeys(sizes['keys_per_person'])
439 self.AddNodes(sizes['nodes_per_site'])
440 self.AddSlices(sizes['slices_per_site'])
441 # create peer and add newly created entities
447 self.UpdateAddressTypes()
448 self.UpdateAddresses()
451 self.UpdateTagTypes()
452 self.UpdateNodeGroups()
454 self.UpdateInterfaces()
457 self.UpdateConfFiles()
459 self.UpdateSliceTags()
462 self.DeleteSliceTags()
465 self.DeleteConfFiles()
468 self.DeleteInterfaces()
471 self.DeleteNodeGroups()
472 self.DeleteTagTypes()
473 self.DeleteAddresses()
474 self.DeleteAddressTypes()
477 # record current (old) objects
478 def RecordStatus (self):
479 self.old_site_ids = [ s['site_id'] for s in self.api.GetSites({},['site_id']) ]
480 self.old_person_ids = [ s['person_id'] for s in self.api.GetPersons({},['person_id']) ]
481 self.old_key_ids = [ s['key_id'] for s in self.api.GetKeys({},['key_id']) ]
482 self.old_node_ids = [ s['node_id'] for s in self.api.GetNodes({},['node_id']) ]
483 self.old_slice_ids = [ s['slice_id'] for s in self.api.GetSlices({},['slice_id']) ]
486 peer_id=self.api.AddPeer (random_peer())
487 peer = GetPeers([peer_id])[0]
489 print("Added peer",peer_id)
491 # add new sites (the ones not in self.site_ids) in the peer
493 for site in self.api.GetSites ({'~site_id':self.old_site_ids}):
494 peer.add_site(site,site['site_id'])
495 for person in self.api.GetPersons ({'~person_id':self.old_person_ids}):
496 peer.add_person(person,person['person_id'])
497 for key in self.api.GetKeys ({'~key_id':self.old_key_ids}):
498 peer.add_key(key,key['key_id'])
499 for node in self.api.GetNodes ({'~node_id':self.old_node_ids}):
500 peer.add_node(node,node['node_id'])
501 for slice in self.api.GetSlices ({'~slice_id':self.old_slice_ids}):
502 peer.add_slice(slice,slice['slice_id'])
504 def AddSites(self, n = 10):
506 Add a number of random sites.
511 site_fields = random_site(self.namelengths)
512 site_id = self.api.AddSite(site_fields)
514 # Should return a unique site_id
515 assert site_id not in self.site_ids
516 self.site_ids.append(site_id)
518 # Enable slice creation
519 site_fields['max_slices'] = randint(1, 10)
520 self.api.UpdateSite(site_id, site_fields)
524 site = self.api.GetSites([site_id])[0]
525 for field in site_fields:
526 assert site[field] == site_fields[field]
529 print("Added site", site_id)
531 def UpdateSites(self):
533 Make random changes to any sites we may have added.
536 for site_id in self.site_ids:
538 site_fields = random_site(self.namelengths)
539 # Do not change login_base
540 if 'login_base' in site_fields:
541 del site_fields['login_base']
542 self.api.UpdateSite(site_id, site_fields)
546 site = self.api.GetSites([site_id])[0]
547 for field in site_fields:
548 assert site[field] == site_fields[field]
551 print("Updated site", site_id)
553 def DeleteSites(self):
555 Delete any random sites we may have added.
558 for site_id in self.site_ids:
559 self.api.DeleteSite(site_id)
562 assert not self.api.GetSites([site_id])
565 print("Deleted site", site_id)
568 assert not self.api.GetSites(self.site_ids)
572 def AddAddressTypes(self, n = 2):
574 Add a number of random address types.
578 address_type_fields = random_address_type()
579 address_type_id = self.api.AddAddressType(address_type_fields)
581 # Should return a unique address_type_id
582 assert address_type_id not in self.address_type_ids
583 self.address_type_ids.append(address_type_id)
587 address_type = self.api.GetAddressTypes([address_type_id])[0]
588 for field in address_type_fields:
589 assert address_type[field] == address_type_fields[field]
592 print("Added address type", address_type_id)
594 def UpdateAddressTypes(self):
596 Make random changes to any address types we may have added.
599 for address_type_id in self.address_type_ids:
600 # Update address_type
601 address_type_fields = random_address_type()
602 self.api.UpdateAddressType(address_type_id, address_type_fields)
606 address_type = self.api.GetAddressTypes([address_type_id])[0]
607 for field in address_type_fields:
608 assert address_type[field] == address_type_fields[field]
611 print("Updated address_type", address_type_id)
613 def DeleteAddressTypes(self):
615 Delete any random address types we may have added.
618 for address_type_id in self.address_type_ids:
619 self.api.DeleteAddressType(address_type_id)
622 assert not self.api.GetAddressTypes([address_type_id])
625 print("Deleted address type", address_type_id)
628 assert not self.api.GetAddressTypes(self.address_type_ids)
630 self.address_type_ids = []
632 def AddAddresses(self, per_site = 2):
634 Add a number of random addresses to each site.
637 for site_id in self.site_ids:
638 for i in range(per_site):
639 address_fields = random_address()
640 address_id = self.api.AddSiteAddress(site_id, address_fields)
642 # Should return a unique address_id
643 assert address_id not in self.address_ids
644 self.address_ids.append(address_id)
646 # Add random address type
647 if self.address_type_ids:
648 for address_type_id in random.sample(self.address_type_ids, 1):
649 self.api.AddAddressTypeToAddress(address_type_id, address_id)
653 address = self.api.GetAddresses([address_id])[0]
654 for field in address_fields:
655 assert address[field] == address_fields[field]
658 print("Added address", address_id, "to site", site_id)
660 def UpdateAddresses(self):
662 Make random changes to any addresses we may have added.
665 for address_id in self.address_ids:
667 address_fields = random_address()
668 self.api.UpdateAddress(address_id, address_fields)
672 address = self.api.GetAddresses([address_id])[0]
673 for field in address_fields:
674 assert address[field] == address_fields[field]
677 print("Updated address", address_id)
679 def DeleteAddresses(self):
681 Delete any random addresses we may have added.
684 for address_id in self.address_ids:
685 # Remove address types
686 address = self.api.GetAddresses([address_id])[0]
687 for address_type_id in address['address_type_ids']:
688 self.api.DeleteAddressTypeFromAddress(address_type_id, address_id)
691 address = self.api.GetAddresses([address_id])[0]
692 assert not address['address_type_ids']
694 self.api.DeleteAddress(address_id)
697 assert not self.api.GetAddresses([address_id])
700 print("Deleted address", address_id)
703 assert not self.api.GetAddresses(self.address_ids)
705 self.address_ids = []
707 def AddPersons(self, per_site = 10):
709 Add a number of random users to each site.
712 for site_id in self.site_ids:
713 for i in range(per_site):
715 person_fields = random_person(self.namelengths)
716 person_id = self.api.AddPerson(person_fields)
718 # Should return a unique person_id
719 assert person_id not in self.person_ids
720 self.person_ids.append(person_id)
724 person = self.api.GetPersons([person_id])[0]
725 for field in person_fields:
726 if field != 'password':
727 assert person[field] == person_fields[field]
729 auth = {'AuthMethod': "password",
730 'Username': person_fields['email'],
731 'AuthString': person_fields['password']}
734 # Check that user is disabled
736 assert not self.api.AuthCheck(auth)
740 # Add random set of roles
741 role_ids = random.sample([20, 30, 40], randint(1, 3))
742 for role_id in role_ids:
743 self.api.AddRoleToPerson(role_id, person_id)
746 person = self.api.GetPersons([person_id])[0]
747 assert set(role_ids) == set(person['role_ids'])
750 self.api.UpdatePerson(person_id, {'enabled': True})
753 # Check that user is enabled
754 assert self.api.AuthCheck(auth)
756 # Associate user with site
757 self.api.AddPersonToSite(person_id, site_id)
758 self.api.SetPersonPrimarySite(person_id, site_id)
761 person = self.api.GetPersons([person_id])[0]
762 assert person['site_ids'][0] == site_id
765 print("Added user", person_id, "to site", site_id)
767 def UpdatePersons(self):
769 Make random changes to any users we may have added.
772 for person_id in self.person_ids:
774 person_fields = random_person(self.namelengths)
776 person_fields['enabled'] = True
777 self.api.UpdatePerson(person_id, person_fields)
781 person = self.api.GetPersons([person_id])[0]
782 for field in person_fields:
783 if field != 'password':
784 assert person[field] == person_fields[field]
787 print("Updated person", person_id)
789 person = self.api.GetPersons([person_id])[0]
791 # Associate user with a random set of sites
792 site_ids = random.sample(self.site_ids, randint(0, len(self.site_ids)))
793 for site_id in (set(site_ids) - set(person['site_ids'])):
794 self.api.AddPersonToSite(person_id, site_id)
795 for site_id in (set(person['site_ids']) - set(site_ids)):
796 self.api.DeletePersonFromSite(person_id, site_id)
799 self.api.SetPersonPrimarySite(person_id, site_ids[0])
802 person = self.api.GetPersons([person_id])[0]
803 assert set(site_ids) == set(person['site_ids'])
806 print("Updated person", person_id, "to sites", site_ids)
808 def DeletePersons(self):
810 Delete any random users we may have added.
813 for person_id in self.person_ids:
815 person = self.api.GetPersons([person_id])[0]
816 for site_id in person['site_ids']:
817 self.api.DeletePersonFromSite(person_id, site_id)
820 person = self.api.GetPersons([person_id])[0]
821 assert not person['site_ids']
824 for role_id in person['role_ids']:
825 self.api.DeleteRoleFromPerson(role_id, person_id)
828 person = self.api.GetPersons([person_id])[0]
829 assert not person['role_ids']
832 self.api.UpdatePerson(person_id, {'enabled': False})
835 person = self.api.GetPersons([person_id])[0]
836 assert not person['enabled']
839 self.api.DeletePerson(person_id)
842 assert not self.api.GetPersons([person_id])
845 print("Deleted user", person_id)
848 assert not self.api.GetPersons(self.person_ids)
852 def AddKeys(self, per_person = 2):
854 Add a number of random keys to each user.
857 key_types = self.api.GetKeyTypes()
859 raise Exception("No key types")
861 for person_id in self.person_ids:
862 for i in range(per_person):
864 key_fields = random_key(key_types,self.namelengths)
865 key_id = self.api.AddPersonKey(person_id, key_fields)
867 # Should return a unique key_id
868 assert key_id not in self.key_ids
869 self.key_ids.append(key_id)
873 key = self.api.GetKeys([key_id])[0]
874 for field in key_fields:
875 assert key[field] == key_fields[field]
877 # Add and immediately blacklist a key
878 key_fields = random_key(key_types,self.namelengths)
879 key_id = self.api.AddPersonKey(person_id, key_fields)
881 self.api.BlacklistKey(key_id)
883 # Is effectively deleted
884 assert not self.api.GetKeys([key_id])
886 # Cannot be added again
888 key_id = self.api.AddPersonKey(person_id, key_fields)
890 except Exception as e:
894 print("Added key", key_id, "to user", person_id)
896 def UpdateKeys(self):
898 Make random changes to any keys we may have added.
901 key_types = self.api.GetKeyTypes()
903 raise Exception("No key types")
905 for key_id in self.key_ids:
907 key_fields = random_key(key_types,self.namelengths)
908 self.api.UpdateKey(key_id, key_fields)
912 key = self.api.GetKeys([key_id])[0]
913 for field in key_fields:
914 assert key[field] == key_fields[field]
917 print("Updated key", key_id)
919 def DeleteKeys(self):
921 Delete any random keys we may have added.
924 for key_id in self.key_ids:
925 self.api.DeleteKey(key_id)
928 assert not self.api.GetKeys([key_id])
931 print("Deleted key", key_id)
934 assert not self.api.GetKeys(self.key_ids)
938 def AddNodeGroups(self, n = 10):
940 Add a number of random node groups.
945 tag_type_id = self.nodegroup_type_ids[i]
946 tagname=self.api.GetTagTypes([tag_type_id])[0]['tagname']
949 groupname = random_nodegroup() ['groupname']
951 nodegroup_id = self.api.AddNodeGroup(groupname, tagname, value)
953 # Should return a unique nodegroup_id
954 assert nodegroup_id not in self.nodegroup_ids
955 self.nodegroup_ids.append(nodegroup_id)
959 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
960 assert nodegroup['groupname'] == groupname
961 assert nodegroup['tagname'] == tagname
962 assert nodegroup['value'] == value
965 print("Added node group", nodegroup_id)
967 def UpdateNodeGroups(self):
969 Make random changes to any node groups we may have added.
972 for nodegroup_id in self.nodegroup_ids:
974 groupname = random_nodegroup()['groupname']
975 # cannot change tagname
976 nodegroup_fields = { 'groupname':groupname }
977 self.api.UpdateNodeGroup(nodegroup_id, nodegroup_fields)
981 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
982 for field in nodegroup_fields:
983 assert nodegroup[field] == nodegroup_fields[field]
986 print("Updated node group", nodegroup_id)
988 def DeleteNodeGroups(self):
990 Delete any random node groups we may have added.
993 for nodegroup_id in self.nodegroup_ids:
994 self.api.DeleteNodeGroup(nodegroup_id)
997 assert not self.api.GetNodeGroups([nodegroup_id])
1000 print("Deleted node group", nodegroup_id)
1003 assert not self.api.GetNodeGroups(self.nodegroup_ids)
1005 self.nodegroup_ids = []
1007 def AddNodes(self, per_site = 2):
1009 Add a number of random nodes to each site. Each node will also
1010 be added to a random node group if AddNodeGroups() was
1014 node_types = self.api.GetNodeTypes()
1016 raise Exception("No node types")
1017 boot_states = self.api.GetBootStates()
1019 raise Exception("No boot states")
1021 for site_id in self.site_ids:
1022 for i in range(per_site):
1024 node_fields = random_node(node_types,boot_states,self.namelengths)
1025 node_id = self.api.AddNode(site_id, node_fields)
1027 # Should return a unique node_id
1028 assert node_id not in self.node_ids
1029 self.node_ids.append(node_id)
1031 # Add to a random set of node groups
1032 nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
1033 for nodegroup_id in nodegroup_ids:
1034 tagname = self.api.GetNodeGroups([nodegroup_id])[0]['tagname']
1035 self.api.AddNodeTag( node_id, tagname, 'yes' )
1039 node = self.api.GetNodes([node_id])[0]
1040 for field in node_fields:
1041 if field not in tag_fields:
1042 assert node[field] == node_fields[field]
1045 print("Added node", node_id)
1047 def UpdateNodes(self):
1049 Make random changes to any nodes we may have added.
1052 node_types = self.api.GetNodeTypes()
1054 raise Exception("No node types")
1055 boot_states = self.api.GetBootStates()
1057 raise Exception("No boot states")
1059 for node_id in self.node_ids:
1061 node_fields = random_node(node_types,boot_states,self.namelengths)
1062 self.api.UpdateNode(node_id, node_fields)
1064 node = self.api.GetNodes([node_id])[0]
1066 # Add to a random set of node groups
1067 nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
1068 for nodegroup_id in (set(nodegroup_ids) - set(node['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,'yes')
1075 node_tag=node_tags[0]
1076 self.api.UpdateNodeTag(node_tag['node_tag_id'],'yes')
1077 for nodegroup_id in (set(node['nodegroup_ids']) - set(nodegroup_ids)):
1078 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
1079 tagname = nodegroup['tagname']
1080 node_tags = self.api.GetNodeTags({'node_id':node_id,'tagname':tagname})
1082 self.api.AddNodeTag(node_id,tagname,'no')
1084 node_tag=node_tags[0]
1085 self.api.UpdateNodeTag(node_tag['node_tag_id'],'no')
1089 node = self.api.GetNodes([node_id])[0]
1090 for field in node_fields:
1091 if field not in tag_fields:
1092 if node[field] != node_fields[field]:
1093 raise Exception("Unexpected field %s in node after GetNodes()"%field)
1094 assert set(nodegroup_ids) == set(node['nodegroup_ids'])
1096 # again but we are now fetching 'arch' explicitly
1097 node2 = self.api.GetNodes([node_id],list(node_fields.keys()))[0]
1098 for field in node_fields:
1099 if node2[field] != node_fields[field]:
1100 raise Exception("Unexpected field %s in node after GetNodes(tags)"%field)
1103 print("Updated node", node_id)
1105 def DeleteNodes(self):
1107 Delete any random nodes we may have added.
1110 for node_id in self.node_ids:
1111 # Remove from node groups
1112 node = self.api.GetNodes([node_id])[0]
1113 for node_tag in self.api.GetNodeTags ( {'node_id': node_id} ):
1114 self.api.UpdateNodeTag(node_tag['node_tag_id'],'')
1117 node = self.api.GetNodes([node_id])[0]
1118 assert not node['nodegroup_ids']
1120 self.api.DeleteNode(node_id)
1123 assert not self.api.GetNodes([node_id])
1126 print("Deleted node", node_id)
1129 assert not self.api.GetNodes(self.node_ids)
1133 def AddInterfaces(self, per_node = 1):
1135 Add a number of random network interfaces to each node.
1138 network_methods = self.api.GetNetworkMethods()
1139 if not network_methods:
1140 raise Exception("No network methods")
1142 network_types = self.api.GetNetworkTypes()
1143 if not network_types:
1144 raise Exception("No network types")
1146 for node_id in self.node_ids:
1147 for i in range(per_node):
1148 method = random.sample(network_methods, 1)[0]
1149 type = random.sample(network_types, 1)[0]
1152 interface_fields = random_interface(method, type,self.namelengths)
1153 interface_id = self.api.AddInterface(node_id, interface_fields)
1155 # Should return a unique interface_id
1156 assert interface_id not in self.interface_ids
1157 self.interface_ids.append(interface_id)
1161 interface = self.api.GetInterfaces([interface_id])[0]
1162 for field in interface_fields:
1163 assert interface[field] == interface_fields[field]
1166 print("Added interface", interface_id, "to node", node_id)
1168 def UpdateInterfaces(self):
1170 Make random changes to any network interfaces we may have added.
1173 network_methods = self.api.GetNetworkMethods()
1174 if not network_methods:
1175 raise Exception("No network methods")
1177 network_types = self.api.GetNetworkTypes()
1178 if not network_types:
1179 raise Exception("No network types")
1181 for interface_id in self.interface_ids:
1182 method = random.sample(network_methods, 1)[0]
1183 type = random.sample(network_types, 1)[0]
1186 interface_fields = random_interface(method, type,self.namelengths)
1187 self.api.UpdateInterface(interface_id, interface_fields)
1191 interface = self.api.GetInterfaces([interface_id])[0]
1192 for field in interface_fields:
1193 assert interface[field] == interface_fields[field]
1196 print("Updated interface", interface_id)
1198 def DeleteInterfaces(self):
1200 Delete any random network interfaces we may have added.
1203 for interface_id in self.interface_ids:
1204 self.api.DeleteInterface(interface_id)
1207 assert not self.api.GetInterfaces([interface_id])
1210 print("Deleted interface", interface_id)
1213 assert not self.api.GetInterfaces(self.interface_ids)
1215 self.interface_ids = []
1217 def AddIlinks (self, n):
1219 Add random links between interfaces.
1223 src = random.sample(self.interface_ids,1)[0]
1224 dst = random.sample(self.interface_ids,1)[0]
1225 ilink_id = self.api.AddIlink (src,dst,
1226 self.ilink_type_ids[i],
1229 assert ilink_id not in self.ilink_ids
1230 self.ilink_ids.append(ilink_id)
1233 print('Added Ilink',ilink_id,' - attached interface',src,'to',dst)
1236 retrieve=GetIlinks({'src_interface_id':src,'dst_interface_id':dst,
1237 'tag_type_id':self.ilink_type_ids[i]})
1238 assert ilink_id==retrieve[0]['ilink_id']
1241 def UpdateIlinks (self):
1243 for ilink_id in self.ilink_ids:
1244 new_value=random_ilink()
1245 self.api.UpdateIlink(ilink_id,new_value)
1248 ilink=self.api.GetIlinks([ilink_id])[0]
1249 assert ilink['value'] == new_value
1252 print('Updated Ilink',ilink_id)
1254 def DeleteIlinks (self):
1255 for ilink_id in self.ilink_ids:
1256 self.api.DeleteIlink(ilink_id)
1259 assert not self.api.GetIlinks({'ilink_id':ilink_id})
1262 print('Deleted Ilink',ilink_id)
1265 assert not self.api.GetIlinks(self.ilink_ids)
1270 def AddPCUs(self, per_site = 1):
1272 Add a number of random PCUs to each site. Each node at the
1273 site will be added to a port on the PCU if AddNodes() was
1277 for site_id in self.site_ids:
1278 for i in range(per_site):
1280 pcu_fields = random_pcu(self.namelengths)
1281 pcu_id = self.api.AddPCU(site_id, pcu_fields)
1283 # Should return a unique pcu_id
1284 assert pcu_id not in self.pcu_ids
1285 self.pcu_ids.append(pcu_id)
1287 # Add each node at this site to a different port on this PCU
1288 site = self.api.GetSites([site_id])[0]
1289 port = randint(1, 10)
1290 for node_id in site['node_ids']:
1291 self.api.AddNodeToPCU(node_id, pcu_id, port)
1296 pcu = self.api.GetPCUs([pcu_id])[0]
1297 for field in pcu_fields:
1298 assert pcu[field] == pcu_fields[field]
1301 print("Added PCU", pcu_id, "to site", site_id)
1303 def UpdatePCUs(self):
1305 Make random changes to any PCUs we may have added.
1308 for pcu_id in self.pcu_ids:
1310 pcu_fields = random_pcu(self.namelengths)
1311 self.api.UpdatePCU(pcu_id, pcu_fields)
1315 pcu = self.api.GetPCUs([pcu_id])[0]
1316 for field in pcu_fields:
1317 assert pcu[field] == pcu_fields[field]
1320 print("Updated PCU", pcu_id)
1322 def DeletePCUs(self):
1324 Delete any random nodes we may have added.
1327 for pcu_id in self.pcu_ids:
1328 # Remove nodes from PCU
1329 pcu = self.api.GetPCUs([pcu_id])[0]
1330 for node_id in pcu['node_ids']:
1331 self.api.DeleteNodeFromPCU(node_id, pcu_id)
1334 pcu = self.api.GetPCUs([pcu_id])[0]
1335 assert not pcu['node_ids']
1337 self.api.DeletePCU(pcu_id)
1340 assert not self.api.GetPCUs([pcu_id])
1343 print("Deleted PCU", pcu_id)
1346 assert not self.api.GetPCUs(self.pcu_ids)
1350 def AddConfFiles(self, n = 10):
1352 Add a number of random global configuration files.
1358 # Add a random configuration file
1359 conf_files.append(random_conf_file())
1362 # Add a nodegroup override file
1363 nodegroup_conf_file = conf_files[0].copy()
1364 nodegroup_conf_file['source'] = randpath(255)
1365 conf_files.append(nodegroup_conf_file)
1367 # Add a node override file
1368 node_conf_file = conf_files[0].copy()
1369 node_conf_file['source'] = randpath(255)
1370 conf_files.append(node_conf_file)
1372 for conf_file_fields in conf_files:
1373 conf_file_id = self.api.AddConfFile(conf_file_fields)
1375 # Should return a unique conf_file_id
1376 assert conf_file_id not in self.conf_file_ids
1377 self.conf_file_ids.append(conf_file_id)
1380 if conf_file_fields == nodegroup_conf_file and self.nodegroup_ids:
1381 nodegroup_id = random.sample(self.nodegroup_ids, 1)[0]
1382 self.api.AddConfFileToNodeGroup(conf_file_id, nodegroup_id)
1387 if conf_file_fields == node_conf_file and self.node_ids:
1388 node_id = random.sample(self.node_ids, 1)[0]
1389 self.api.AddConfFileToNode(conf_file_id, node_id)
1394 # Check configuration file
1395 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1396 for field in conf_file_fields:
1397 assert conf_file[field] == conf_file_fields[field]
1400 print("Added configuration file", conf_file_id, end=' ')
1401 if nodegroup_id is not None:
1402 print("to node group", nodegroup_id, end=' ')
1403 elif node_id is not None:
1404 print("to node", node_id, end=' ')
1407 def UpdateConfFiles(self):
1409 Make random changes to any configuration files we may have added.
1412 for conf_file_id in self.conf_file_ids:
1413 # Update configuration file
1414 conf_file_fields = random_conf_file()
1415 # Do not update dest so that it remains an override if set
1416 if 'dest' in conf_file_fields:
1417 del conf_file_fields['dest']
1418 self.api.UpdateConfFile(conf_file_id, conf_file_fields)
1421 # Check configuration file
1422 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1423 for field in conf_file_fields:
1424 assert conf_file[field] == conf_file_fields[field]
1427 print("Updated configuration file", conf_file_id)
1429 def DeleteConfFiles(self):
1431 Delete any random configuration files we may have added.
1434 for conf_file_id in self.conf_file_ids:
1435 self.api.DeleteConfFile(conf_file_id)
1438 assert not self.api.GetConfFiles([conf_file_id])
1441 print("Deleted configuration file", conf_file_id)
1444 assert not self.api.GetConfFiles(self.conf_file_ids)
1446 self.conf_file_ids = []
1448 def AddTagTypes(self,n_sa,n_ng,n_il):
1450 Add as many tag types as there are nodegroups,
1451 will use value=yes for each nodegroup
1454 roles = self.api.GetRoles()
1456 raise Exception("No roles")
1457 role_ids = [role['role_id'] for role in roles]
1459 for i in range (n_sa + n_ng + n_il):
1460 tag_type_fields = random_tag_type (role_ids)
1461 tag_type_id = self.api.AddTagType (tag_type_fields)
1463 assert tag_type_id not in \
1464 self.slice_type_ids + \
1465 self.nodegroup_type_ids + \
1468 tt_role_ids=random_roles(role_ids)
1469 for tt_role_id in tt_role_ids:
1470 self.api.AddRoleToTagType(tt_role_id,tag_type_id)
1473 self.slice_type_ids.append(tag_type_id)
1474 elif i < n_sa+n_ng :
1475 self.nodegroup_type_ids.append(tag_type_id)
1477 self.ilink_type_ids.append(tag_type_id)
1480 tag_type = self.api.GetTagTypes([tag_type_id])[0]
1481 for field in tag_type_fields:
1482 assert tag_type[field] == tag_type_fields[field]
1483 for tt_role_id in tt_role_ids:
1484 assert tt_role_id in tag_type['role_ids']
1486 print("Created tag type", tag_type_id)
1488 def UpdateTagTypes(self):
1490 Make random changes to any slice attribute types we may have added.
1493 roles = self.api.GetRoles()
1495 raise Exception("No roles")
1496 role_ids = [role['role_id'] for role in roles]
1498 for tag_type_id in self.slice_type_ids + self.nodegroup_type_ids + self.ilink_type_ids:
1499 # Update slice attribute type
1500 tag_type_fields = random_tag_type(role_ids)
1501 self.api.UpdateTagType(tag_type_id, tag_type_fields)
1504 # Check slice attribute type
1505 tag_type = self.api.GetTagTypes([tag_type_id])[0]
1506 for field in tag_type_fields:
1507 assert tag_type[field] == tag_type_fields[field]
1509 print("Updated tag type", tag_type_id)
1511 def DeleteTagTypes(self):
1513 Delete any random slice attribute types we may have added.
1516 for tag_type_id in self.slice_type_ids + self.nodegroup_type_ids + self.ilink_type_ids:
1517 self.api.DeleteTagType(tag_type_id)
1520 assert not self.api.GetTagTypes([tag_type_id])
1523 print("Deleted tag type", tag_type_id)
1526 assert not self.api.GetTagTypes(self.slice_type_ids+self.nodegroup_type_ids+self.ilink_type_ids)
1528 self.slice_type_ids = []
1529 self.nodegroup_type_ids = []
1531 def AddSlices(self, per_site = 10):
1533 Add a number of random slices per site.
1536 for site in self.api.GetSites(self.site_ids):
1537 for i in range(min(per_site, site['max_slices'])):
1539 slice_fields = random_slice(site['login_base'],self.namelengths)
1540 slice_id = self.api.AddSlice(slice_fields)
1542 # Should return a unique slice_id
1543 assert slice_id not in self.slice_ids
1544 self.slice_ids.append(slice_id)
1546 # Add slice to a random set of nodes
1547 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1549 self.api.AddSliceToNodes(slice_id, node_ids)
1551 # Add random set of site users to slice
1552 person_ids = random.sample(site['person_ids'], randint(0, len(site['person_ids'])))
1553 for person_id in person_ids:
1554 self.api.AddPersonToSlice(person_id, slice_id)
1558 slice = self.api.GetSlices([slice_id])[0]
1559 for field in slice_fields:
1560 assert slice[field] == slice_fields[field]
1562 assert set(node_ids) == set(slice['node_ids'])
1563 assert set(person_ids) == set(slice['person_ids'])
1566 print("Added slice", slice_id, "to site", site['site_id'], end=' ')
1568 print("and nodes", node_ids, end=' ')
1571 print("Added users", site['person_ids'], "to slice", slice_id)
1573 def UpdateSlices(self):
1575 Make random changes to any slices we may have added.
1578 for slice_id in self.slice_ids:
1580 slice_fields = random_slice("unused",self.namelengths)
1581 # Cannot change slice name
1582 if 'name' in slice_fields:
1583 del slice_fields['name']
1584 self.api.UpdateSlice(slice_id, slice_fields)
1586 slice = self.api.GetSlices([slice_id])[0]
1588 # Add slice to a random set of nodes
1589 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1590 self.api.AddSliceToNodes(slice_id, list(set(node_ids) - set(slice['node_ids'])))
1591 self.api.DeleteSliceFromNodes(slice_id, list(set(slice['node_ids']) - set(node_ids)))
1593 # Add random set of users to slice
1594 person_ids = random.sample(self.person_ids, randint(0, len(self.person_ids)))
1595 for person_id in (set(person_ids) - set(slice['person_ids'])):
1596 self.api.AddPersonToSlice(person_id, slice_id)
1597 for person_id in (set(slice['person_ids']) - set(person_ids)):
1598 self.api.DeletePersonFromSlice(person_id, slice_id)
1601 slice = self.api.GetSlices([slice_id])[0]
1602 for field in slice_fields:
1603 assert slice[field] == slice_fields[field]
1604 assert set(node_ids) == set(slice['node_ids'])
1605 assert set(person_ids) == set(slice['person_ids'])
1608 print("Updated slice", slice_id)
1609 print("Added nodes", node_ids, "to slice", slice_id)
1610 print("Added persons", person_ids, "to slice", slice_id)
1612 def DeleteSlices(self):
1614 Delete any random slices we may have added.
1617 for slice_id in self.slice_ids:
1618 self.api.DeleteSlice(slice_id)
1621 assert not self.api.GetSlices([slice_id])
1624 print("Deleted slice", slice_id)
1627 assert not self.api.GetSlices(self.slice_ids)
1631 def AddSliceTags(self, per_slice = 2):
1633 Add a number of random slices per site.
1636 if not self.slice_type_ids:
1639 for slice_id in self.slice_ids:
1640 slice = self.api.GetSlices([slice_id])[0]
1642 for i in range(per_slice):
1643 # Set a random slice/sliver attribute
1644 for tag_type_id in random.sample(self.slice_type_ids, 1):
1645 value = randstr(16, letters + '_' + digits)
1646 # Make it a sliver attribute with 50% probability
1647 if slice['node_ids']:
1648 node_id = random.sample(slice['node_ids'] + [None] * len(slice['node_ids']), 1)[0]
1652 # Add slice attribute
1654 slice_tag_id = self.api.AddSliceTag(slice_id, tag_type_id, value)
1656 slice_tag_id = self.api.AddSliceTag(slice_id, tag_type_id, value, node_id)
1658 # Should return a unique slice_tag_id
1659 assert slice_tag_id not in self.slice_tag_ids
1660 self.slice_tag_ids.append(slice_tag_id)
1663 # Check slice attribute
1664 slice_tag = self.api.GetSliceTags([slice_tag_id])[0]
1665 for field in 'tag_type_id', 'slice_id', 'node_id', 'slice_tag_id', 'value':
1666 assert slice_tag[field] == locals()[field]
1669 print("Added slice attribute", slice_tag_id, "of type", tag_type_id, end=' ')
1670 if node_id is not None:
1671 print("to node", node_id, end=' ')
1674 def UpdateSliceTags(self):
1676 Make random changes to any slice attributes we may have added.
1679 for slice_tag_id in self.slice_tag_ids:
1680 # Update slice attribute
1681 value = randstr(16, letters + '_' + digits)
1682 self.api.UpdateSliceTag(slice_tag_id, value)
1684 # Check slice attribute again
1685 slice_tag = self.api.GetSliceTags([slice_tag_id])[0]
1686 assert slice_tag['value'] == value
1689 print("Updated slice attribute", slice_tag_id)
1691 def DeleteSliceTags(self):
1693 Delete any random slice attributes we may have added.
1696 for slice_tag_id in self.slice_tag_ids:
1697 self.api.DeleteSliceTag(slice_tag_id)
1700 assert not self.api.GetSliceTags([slice_tag_id])
1703 print("Deleted slice attribute", slice_tag_id)
1706 assert not self.api.GetSliceTags(self.slice_tag_ids)
1708 self.slice_tag_ids = []
1710 # convenience for cleaning up
1711 # not exactly accurate -- use on test plcs only
1712 def WipeSitesFromLength(self):
1713 for site in self.api.GetSites():
1714 abbrev=site['abbreviated_name']
1715 # print 'matching',len(abbrev),'against',self.namelengths['abbreviated_name']
1716 if len(abbrev)==self.namelengths['abbreviated_name']:
1717 # if len(abbrev)==17:
1718 print('wiping site %d (%s)'%(site['site_id'],site['name']))
1719 self.api.DeleteSite(site['site_id'])
1722 parser = OptionParser()
1723 parser.add_option("-c", "--check", action = "store_true", default = False,
1724 help = "Check most actions (default: %default)")
1725 parser.add_option("-q", "--quiet", action = "store_true", default = False,
1726 help = "Be quiet (default: %default)")
1727 parser.add_option("-p","--preserve", action="store_true", default =False,
1728 help = "Do not delete created objects")
1729 parser.add_option("-t", "--tiny", action = "store_true", default = False,
1730 help = "Run a tiny test (default: %default)")
1731 parser.add_option("-l", "--large", action = "store_true", default = False,
1732 help = "Run a large test (default: %default)")
1733 parser.add_option("-x", "--xlarge", action = "store_true", default = False,
1734 help = "Run an XL test (default: %default)")
1735 parser.add_option("-s", "--short-names", action="store_true", dest="short_names", default = False,
1736 help = "Generate smaller names for checking UI rendering")
1737 parser.add_option ("-f", "--foreign", action="store_true", dest="federating", default = False,
1738 help = "Create a fake peer and add items in it (no update, no delete)")
1739 parser.add_option ("-w", "--wipe", action="store_true", dest="wipe", default = False,
1740 help = "Wipe sites whose abbrev matches what the tests created")
1741 (options, args) = parser.parse_args()
1743 test = Test(api = Shell(),
1744 check = options.check,
1745 verbose = not options.quiet,
1746 preserve = options.preserve,
1747 federating = options.federating)
1749 if options.short_names:
1750 test.namelengths = Test.namelengths_short
1752 test.namelengths = Test.namelengths_default
1755 test.WipeSitesFromLength()
1759 sizes = Test.sizes_tiny
1761 sizes = Test.sizes_large
1762 elif options.xlarge:
1763 sizes = Test.sizes_xlarge
1765 sizes = Test.sizes_default
1768 if __name__ == "__main__":