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 def randfloat(min = 0.0, max = 1.0):
27 return float(min) + (random.random() * (float(max) - float(min)))
29 def randint(min = 0, max = 1):
30 return int(randfloat(min, max + 1))
32 # See "2.2 Characters" in the XML specification:
34 # #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
36 # [#x7F-#x84], [#x86-#x9F], [#xFDD0-#xFDDF]
39 ascii_xml_chars = map(unichr, [0x9, 0xA])
40 # xmlrpclib uses xml.parsers.expat, which always converts either '\r'
41 # (#xD) or '\n' (#xA) to '\n'. So avoid using '\r', too, if this is
43 if xmlrpclib.loads(xmlrpclib.dumps(('\r',)))[0][0] == '\r':
44 ascii_xml_chars.append('\r')
45 ascii_xml_chars += map(unichr, xrange(0x20, 0x7F - 1))
46 low_xml_chars = list(ascii_xml_chars)
47 low_xml_chars += map(unichr, xrange(0x84 + 1, 0x86 - 1))
48 low_xml_chars += map(unichr, xrange(0x9F + 1, 0xFF))
49 valid_xml_chars = list(low_xml_chars)
50 valid_xml_chars += map(unichr, xrange(0xFF + 1, 0xD7FF))
51 valid_xml_chars += map(unichr, xrange(0xE000, 0xFDD0 - 1))
52 valid_xml_chars += map(unichr, xrange(0xFDDF + 1, 0xFFFD))
54 def randstr(length, pool = valid_xml_chars, encoding = "utf-8"):
55 sample = random.sample(pool, min(length, len(pool)))
58 bytes = len(s.encode(encoding))
62 sample += random.sample(pool, min(length - bytes, len(pool)))
63 random.shuffle(sample)
68 # nasty - see Test.namelengths* below
72 # 1. Each part begins and ends with a letter or number.
73 # 2. Each part except the last can contain letters, numbers, or hyphens.
74 # 3. Each part is between 1 and 64 characters, including the trailing dot.
75 # 4. At least two parts.
76 # 5. Last part can only contain between 2 and 6 letters.
77 hostname = 'a' + randstr(namelengths['hostname1'], letters + digits + '-') + '1.' + \
78 'b' + randstr(namelengths['hostname1'], letters + digits + '-') + '2.' + \
79 'c' + randstr(namelengths['hostname2'], letters)
84 for i in range(randint(1, 10)):
85 parts.append(randstr(randint(1, 30), ascii_xml_chars))
86 return u'/'.join(parts)[0:length]
89 return (randstr(namelengths['email'], letters + digits) + "@" + randhostname()).lower()
91 def randkey(bits = 2048):
92 ssh_key_types = ["ssh-dss", "ssh-rsa"]
93 key_type = random.sample(ssh_key_types, 1)[0]
94 return ' '.join([key_type,
95 base64.b64encode(''.join(randstr(bits / 8).encode("utf-8"))),
100 sitename=randstr(namelengths['sitename'],namelengths['sitename_contents'])
102 sitename=randstr(namelengths['sitename'])
104 abbreviated_name=randstr(namelengths['abbreviated_name'],namelengths['abbreviated_name_contents'])
106 abbreviated_name=randstr(namelengths['abbreviated_name'])
110 'abbreviated_name': abbreviated_name,
111 'login_base': randstr(namelengths['login_base'], letters).lower(),
112 'latitude': int(randfloat(-90.0, 90.0) * 1000) / 1000.0,
113 'longitude': int(randfloat(-180.0, 180.0) * 1000) / 1000.0,
116 def random_address_type():
119 'description': randstr(254),
122 def random_address():
124 'line1': randstr(254),
125 'line2': randstr(254),
126 'line3': randstr(254),
127 'city': randstr(254),
128 'state': randstr(254),
129 'postalcode': randstr(64),
130 'country': randstr(128),
135 'first_name': randstr(namelengths['first_name']),
136 'last_name': randstr(namelengths['last_name']),
137 'email': randemail(),
139 # Accounts are disabled by default
141 'password': randstr(254),
144 def random_key(key_types):
146 'key_type': random.sample(key_types, 1)[0],
150 def random_tag_type (role_ids):
151 return {'tagname': randstr(12),
152 'category':randstr(8),
153 'min_role_id': random.sample(role_ids, 1)[0],
154 'description' : randstr(128),
157 def random_nodegroup():
158 return {'groupname' : randstr(50) }
161 def random_node(node_types,boot_states):
163 'hostname': randhostname(),
164 'node_type': random.sample(node_types,1)[0],
165 'boot_state': random.sample(boot_states, 1)[0],
166 'model': randstr(namelengths['model']),
167 'version': randstr(64),
168 # for testing node tags
172 def random_interface(method, type):
176 'bwlimit': randint(500000, 10000000),
180 ip = randint(0, 0xffffffff)
181 netmask = (0xffffffff << randint(2, 31)) & 0xffffffff
182 network = ip & netmask
183 broadcast = ((ip & netmask) | ~netmask) & 0xffffffff
184 gateway = randint(network + 1, broadcast - 1)
185 dns1 = randint(0, 0xffffffff)
187 for field in 'ip', 'netmask', 'network', 'broadcast', 'gateway', 'dns1':
188 interface_fields[field] = socket.inet_ntoa(struct.pack('>L', locals()[field]))
190 return interface_fields
197 'hostname': randhostname(),
198 'ip': socket.inet_ntoa(struct.pack('>L', randint(0, 0xffffffff))),
199 'protocol': randstr(16),
200 'username': randstr(254),
201 'password': randstr(254),
202 'notes': randstr(254),
203 'model': randstr(32),
206 def random_conf_file():
208 'enabled': bool(randint()),
209 'source': randpath(255),
210 'dest': randpath(255),
211 'file_permissions': "%#o" % randint(0, 512),
212 'file_owner': randstr(32, letters + '_' + digits),
213 'file_group': randstr(32, letters + '_' + digits),
214 'preinstall_cmd': randpath(100),
215 'postinstall_cmd': randpath(100),
216 'error_cmd': randpath(100),
217 'ignore_cmd_errors': bool(randint()),
218 'always_update': bool(randint()),
221 def random_slice(login_base):
223 'name': login_base + "_" + randstr(11, letters).lower(),
224 'url': "http://" + randhostname() + "/",
225 'description': randstr(2048),
232 'addresses_per_site': 1,
233 'persons_per_site': 1,
234 'keys_per_person': 1,
238 'interfaces_per_node': 1,
242 'slices_per_site': 1,
243 'attributes_per_slice': 1,
249 'addresses_per_site': 2,
250 'persons_per_site': 4,
251 'keys_per_person': 2,
255 'interfaces_per_node': 1,
259 'slices_per_site': 4,
260 'attributes_per_slice': 2,
263 namelengths_default = {
268 'abbreviated_name':50,
275 namelengths_short = {
280 'sitename_contents':letters+digits+whitespace+punctuation,
281 'abbreviated_name':24,
282 'abbreviated_name_contents':letters+digits+whitespace+punctuation,
289 def __init__(self, api, check = True, verbose = True, preserve = False):
292 self.verbose = verbose
293 self.preserve = preserve
296 self.address_type_ids = []
297 self.address_ids = []
300 self.slice_type_ids = []
301 self.nodegroup_type_ids = []
302 self.ilink_type_ids = []
303 self.nodegroup_ids = []
305 self.interface_ids = []
308 self.conf_file_ids = []
310 self.slice_tag_ids = []
312 def Cardinals (self):
313 return [len(x) for x in (
314 self.api.GetNodes({},['node_id']),
315 self.api.GetSites({},['site_id']),
316 self.api.GetPersons({},['person_id']),
317 self.api.GetSlices({},['slice_id']),
320 def Run(self, **kwds):
322 Run a complete database and API consistency test. Populates
323 the database with a set of random entities, updates them, then
324 deletes them. Examples:
326 test.Run() # Defaults
327 test.Run(**Test.sizes_default) # Defaults
328 test.Run(**Test.sizes_tiny) # Tiny set
329 test.Run(sites = 123, slices_per_site = 4) # Defaults with overrides
332 cardinals_before=self.Cardinals()
333 print 'Cardinals before test (n,s,p,sl)',cardinals_before
338 print 'Preserving - delete skipped'
342 cardinals_after=self.Cardinals()
343 print 'Cardinals after test (n,s,p,sl)',cardinals_after
345 if cardinals_before != cardinals_after:
346 raise Exception, 'cardinals before and after differ - check deletion mechanisms'
348 def Add(self, **kwds):
350 Populate the database with a set of random entities. Examples:
355 sizes = self.sizes_default.copy()
358 self.AddSites(sizes['sites'])
359 self.AddAddressTypes(sizes['address_types'])
360 self.AddAddresses(sizes['addresses_per_site'])
361 self.AddPersons(sizes['persons_per_site'])
362 self.AddKeys(sizes['keys_per_person'])
363 self.AddTagTypes(sizes['slice_tags'],sizes['nodegroups'],sizes['ilinks'])
364 self.AddNodeGroups(sizes['nodegroups'])
365 self.AddNodes(sizes['nodes_per_site'])
366 self.AddInterfaces(sizes['interfaces_per_node'])
367 self.AddIlinks (sizes['ilinks'])
368 self.AddPCUs(sizes['pcus_per_site'])
369 self.AddConfFiles(sizes['conf_files'])
370 self.AddSlices(sizes['slices_per_site'])
371 self.AddSliceTags(sizes['attributes_per_slice'])
375 self.UpdateAddressTypes()
376 self.UpdateAddresses()
379 self.UpdateTagTypes()
380 self.UpdateNodeGroups()
382 self.UpdateInterfaces()
385 self.UpdateConfFiles()
387 self.UpdateSliceTags()
390 self.DeleteSliceTags()
393 self.DeleteConfFiles()
396 self.DeleteInterfaces()
399 self.DeleteNodeGroups()
400 self.DeleteTagTypes()
401 self.DeleteAddresses()
402 self.DeleteAddressTypes()
405 def AddSites(self, n = 10):
407 Add a number of random sites.
412 site_fields = random_site()
413 site_id = self.api.AddSite(site_fields)
415 # Should return a unique site_id
416 assert site_id not in self.site_ids
417 self.site_ids.append(site_id)
419 # Enable slice creation
420 site_fields['max_slices'] = randint(1, 10)
421 self.api.UpdateSite(site_id, site_fields)
425 site = self.api.GetSites([site_id])[0]
426 for field in site_fields:
427 assert site[field] == site_fields[field]
430 print "Added site", site_id
432 def UpdateSites(self):
434 Make random changes to any sites we may have added.
437 for site_id in self.site_ids:
439 site_fields = random_site()
440 # Do not change login_base
441 if 'login_base' in site_fields:
442 del site_fields['login_base']
443 self.api.UpdateSite(site_id, site_fields)
447 site = self.api.GetSites([site_id])[0]
448 for field in site_fields:
449 assert site[field] == site_fields[field]
452 print "Updated site", site_id
454 def DeleteSites(self):
456 Delete any random sites we may have added.
459 for site_id in self.site_ids:
460 self.api.DeleteSite(site_id)
463 assert not self.api.GetSites([site_id])
466 print "Deleted site", site_id
469 assert not self.api.GetSites(self.site_ids)
473 def AddAddressTypes(self, n = 2):
475 Add a number of random address types.
479 address_type_fields = random_address_type()
480 address_type_id = self.api.AddAddressType(address_type_fields)
482 # Should return a unique address_type_id
483 assert address_type_id not in self.address_type_ids
484 self.address_type_ids.append(address_type_id)
488 address_type = self.api.GetAddressTypes([address_type_id])[0]
489 for field in address_type_fields:
490 assert address_type[field] == address_type_fields[field]
493 print "Added address type", address_type_id
495 def UpdateAddressTypes(self):
497 Make random changes to any address types we may have added.
500 for address_type_id in self.address_type_ids:
501 # Update address_type
502 address_type_fields = random_address_type()
503 self.api.UpdateAddressType(address_type_id, address_type_fields)
507 address_type = self.api.GetAddressTypes([address_type_id])[0]
508 for field in address_type_fields:
509 assert address_type[field] == address_type_fields[field]
512 print "Updated address_type", address_type_id
514 def DeleteAddressTypes(self):
516 Delete any random address types we may have added.
519 for address_type_id in self.address_type_ids:
520 self.api.DeleteAddressType(address_type_id)
523 assert not self.api.GetAddressTypes([address_type_id])
526 print "Deleted address type", address_type_id
529 assert not self.api.GetAddressTypes(self.address_type_ids)
531 self.address_type_ids = []
533 def AddAddresses(self, per_site = 2):
535 Add a number of random addresses to each site.
538 for site_id in self.site_ids:
539 for i in range(per_site):
540 address_fields = random_address()
541 address_id = self.api.AddSiteAddress(site_id, address_fields)
543 # Should return a unique address_id
544 assert address_id not in self.address_ids
545 self.address_ids.append(address_id)
547 # Add random address type
548 if self.address_type_ids:
549 for address_type_id in random.sample(self.address_type_ids, 1):
550 self.api.AddAddressTypeToAddress(address_type_id, address_id)
554 address = self.api.GetAddresses([address_id])[0]
555 for field in address_fields:
556 assert address[field] == address_fields[field]
559 print "Added address", address_id, "to site", site_id
561 def UpdateAddresses(self):
563 Make random changes to any addresses we may have added.
566 for address_id in self.address_ids:
568 address_fields = random_address()
569 self.api.UpdateAddress(address_id, address_fields)
573 address = self.api.GetAddresses([address_id])[0]
574 for field in address_fields:
575 assert address[field] == address_fields[field]
578 print "Updated address", address_id
580 def DeleteAddresses(self):
582 Delete any random addresses we may have added.
585 for address_id in self.address_ids:
586 # Remove address types
587 address = self.api.GetAddresses([address_id])[0]
588 for address_type_id in address['address_type_ids']:
589 self.api.DeleteAddressTypeFromAddress(address_type_id, address_id)
592 address = self.api.GetAddresses([address_id])[0]
593 assert not address['address_type_ids']
595 self.api.DeleteAddress(address_id)
598 assert not self.api.GetAddresses([address_id])
601 print "Deleted address", address_id
604 assert not self.api.GetAddresses(self.address_ids)
606 self.address_ids = []
608 def AddPersons(self, per_site = 10):
610 Add a number of random users to each site.
613 for site_id in self.site_ids:
614 for i in range(per_site):
616 person_fields = random_person()
617 person_id = self.api.AddPerson(person_fields)
619 # Should return a unique person_id
620 assert person_id not in self.person_ids
621 self.person_ids.append(person_id)
625 person = self.api.GetPersons([person_id])[0]
626 for field in person_fields:
627 if field != 'password':
628 assert person[field] == person_fields[field]
630 auth = {'AuthMethod': "password",
631 'Username': person_fields['email'],
632 'AuthString': person_fields['password']}
635 # Check that user is disabled
637 assert not self.api.AuthCheck(auth)
641 # Add random set of roles
642 role_ids = random.sample([20, 30, 40], randint(1, 3))
643 for role_id in role_ids:
644 self.api.AddRoleToPerson(role_id, person_id)
647 person = self.api.GetPersons([person_id])[0]
648 assert set(role_ids) == set(person['role_ids'])
651 self.api.UpdatePerson(person_id, {'enabled': True})
654 # Check that user is enabled
655 assert self.api.AuthCheck(auth)
657 # Associate user with site
658 self.api.AddPersonToSite(person_id, site_id)
659 self.api.SetPersonPrimarySite(person_id, site_id)
662 person = self.api.GetPersons([person_id])[0]
663 assert person['site_ids'][0] == site_id
666 print "Added user", person_id, "to site", site_id
668 def UpdatePersons(self):
670 Make random changes to any users we may have added.
673 for person_id in self.person_ids:
675 person_fields = random_person()
677 person_fields['enabled'] = True
678 self.api.UpdatePerson(person_id, person_fields)
682 person = self.api.GetPersons([person_id])[0]
683 for field in person_fields:
684 if field != 'password':
685 assert person[field] == person_fields[field]
688 print "Updated person", person_id
690 person = self.api.GetPersons([person_id])[0]
692 # Associate user with a random set of sites
693 site_ids = random.sample(self.site_ids, randint(0, len(self.site_ids)))
694 for site_id in (set(site_ids) - set(person['site_ids'])):
695 self.api.AddPersonToSite(person_id, site_id)
696 for site_id in (set(person['site_ids']) - set(site_ids)):
697 self.api.DeletePersonFromSite(person_id, site_id)
700 self.api.SetPersonPrimarySite(person_id, site_ids[0])
703 person = self.api.GetPersons([person_id])[0]
704 assert set(site_ids) == set(person['site_ids'])
707 print "Updated person", person_id, "to sites", site_ids
709 def DeletePersons(self):
711 Delete any random users we may have added.
714 for person_id in self.person_ids:
716 person = self.api.GetPersons([person_id])[0]
717 for site_id in person['site_ids']:
718 self.api.DeletePersonFromSite(person_id, site_id)
721 person = self.api.GetPersons([person_id])[0]
722 assert not person['site_ids']
725 for role_id in person['role_ids']:
726 self.api.DeleteRoleFromPerson(role_id, person_id)
729 person = self.api.GetPersons([person_id])[0]
730 assert not person['role_ids']
733 self.api.UpdatePerson(person_id, {'enabled': False})
736 person = self.api.GetPersons([person_id])[0]
737 assert not person['enabled']
740 self.api.DeletePerson(person_id)
743 assert not self.api.GetPersons([person_id])
746 print "Deleted user", person_id
749 assert not self.api.GetPersons(self.person_ids)
753 def AddKeys(self, per_person = 2):
755 Add a number of random keys to each user.
758 key_types = self.api.GetKeyTypes()
760 raise Exception, "No key types"
762 for person_id in self.person_ids:
763 for i in range(per_person):
765 key_fields = random_key(key_types)
766 key_id = self.api.AddPersonKey(person_id, key_fields)
768 # Should return a unique key_id
769 assert key_id not in self.key_ids
770 self.key_ids.append(key_id)
774 key = self.api.GetKeys([key_id])[0]
775 for field in key_fields:
776 assert key[field] == key_fields[field]
778 # Add and immediately blacklist a key
779 key_fields = random_key(key_types)
780 key_id = self.api.AddPersonKey(person_id, key_fields)
782 self.api.BlacklistKey(key_id)
784 # Is effectively deleted
785 assert not self.api.GetKeys([key_id])
787 # Cannot be added again
789 key_id = self.api.AddPersonKey(person_id, key_fields)
795 print "Added key", key_id, "to user", person_id
797 def UpdateKeys(self):
799 Make random changes to any keys we may have added.
802 key_types = self.api.GetKeyTypes()
804 raise Exception, "No key types"
806 for key_id in self.key_ids:
808 key_fields = random_key(key_types)
809 self.api.UpdateKey(key_id, key_fields)
813 key = self.api.GetKeys([key_id])[0]
814 for field in key_fields:
815 assert key[field] == key_fields[field]
818 print "Updated key", key_id
820 def DeleteKeys(self):
822 Delete any random keys we may have added.
825 for key_id in self.key_ids:
826 self.api.DeleteKey(key_id)
829 assert not self.api.GetKeys([key_id])
832 print "Deleted key", key_id
835 assert not self.api.GetKeys(self.key_ids)
839 def AddNodeGroups(self, n = 10):
841 Add a number of random node groups.
846 tag_type_id = self.nodegroup_type_ids[i]
847 tagname=self.api.GetTagTypes([tag_type_id])[0]['tagname']
850 groupname = random_nodegroup() ['groupname']
852 nodegroup_id = self.api.AddNodeGroup(groupname, tagname, value)
854 # Should return a unique nodegroup_id
855 assert nodegroup_id not in self.nodegroup_ids
856 self.nodegroup_ids.append(nodegroup_id)
860 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
861 assert nodegroup['groupname'] == groupname
862 assert nodegroup['tagname'] == tagname
863 assert nodegroup['value'] == value
866 print "Added node group", nodegroup_id
868 def UpdateNodeGroups(self):
870 Make random changes to any node groups we may have added.
873 for nodegroup_id in self.nodegroup_ids:
875 groupname = random_nodegroup()['groupname']
876 # cannot change tagname
877 nodegroup_fields = { 'groupname':groupname }
878 self.api.UpdateNodeGroup(nodegroup_id, nodegroup_fields)
882 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
883 for field in nodegroup_fields:
884 assert nodegroup[field] == nodegroup_fields[field]
887 print "Updated node group", nodegroup_id
889 def DeleteNodeGroups(self):
891 Delete any random node groups we may have added.
894 for nodegroup_id in self.nodegroup_ids:
895 self.api.DeleteNodeGroup(nodegroup_id)
898 assert not self.api.GetNodeGroups([nodegroup_id])
901 print "Deleted node group", nodegroup_id
904 assert not self.api.GetNodeGroups(self.nodegroup_ids)
906 self.nodegroup_ids = []
908 def AddNodes(self, per_site = 2):
910 Add a number of random nodes to each site. Each node will also
911 be added to a random node group if AddNodeGroups() was
915 node_types = self.api.GetNodeTypes()
917 raise Exception, "No node types"
918 boot_states = self.api.GetBootStates()
920 raise Exception, "No boot states"
922 for site_id in self.site_ids:
923 for i in range(per_site):
925 node_fields = random_node(node_types,boot_states)
926 node_id = self.api.AddNode(site_id, node_fields)
928 # Should return a unique node_id
929 assert node_id not in self.node_ids
930 self.node_ids.append(node_id)
932 # Add to a random set of node groups
933 nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
934 for nodegroup_id in nodegroup_ids:
935 tagname = self.api.GetNodeGroups([nodegroup_id])[0]['tagname']
936 self.api.AddNodeTag( node_id, tagname, 'yes' )
940 node = self.api.GetNodes([node_id])[0]
941 for field in node_fields:
942 if field not in tag_fields:
943 assert node[field] == node_fields[field]
946 print "Added node", node_id
948 def UpdateNodes(self):
950 Make random changes to any nodes we may have added.
953 node_types = self.api.GetNodeTypes()
955 raise Exception, "No node types"
956 boot_states = self.api.GetBootStates()
958 raise Exception, "No boot states"
960 for node_id in self.node_ids:
962 node_fields = random_node(node_types,boot_states)
963 self.api.UpdateNode(node_id, node_fields)
965 node = self.api.GetNodes([node_id])[0]
967 # Add to a random set of node groups
968 nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
969 for nodegroup_id in (set(nodegroup_ids) - set(node['nodegroup_ids'])):
970 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
971 tagname = nodegroup['tagname']
972 node_tags = self.api.GetNodeTags({'node_id':node_id,'tagname':tagname})
974 self.api.AddNodeTag(node_id,tagname,'yes')
976 node_tag=node_tags[0]
977 self.api.UpdateNodeTag(node_tag['node_tag_id'],'yes')
978 for nodegroup_id in (set(node['nodegroup_ids']) - set(nodegroup_ids)):
979 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
980 tagname = nodegroup['tagname']
981 node_tags = self.api.GetNodeTags({'node_id':node_id,'tagname':tagname})
983 self.api.AddNodeTag(node_id,tagname,'no')
985 node_tag=node_tags[0]
986 self.api.UpdateNodeTag(node_tag['node_tag_id'],'no')
990 node = self.api.GetNodes([node_id])[0]
991 for field in node_fields:
992 if field not in tag_fields:
993 if node[field] != node_fields[field]:
994 raise Exception, "Unexpected field %s in node after GetNodes()"%field
995 assert set(nodegroup_ids) == set(node['nodegroup_ids'])
997 print 'WARNING: skipping updatenode with tags as this is not implemented yet'
998 # again when fetching 'arch' explicitly
999 node2 = self.api.GetNodes([node_id],node_fields.keys())[0]
1000 for field in node_fields:
1001 if node2[field] != node_fields[field]:
1002 raise Exception, "Unexpected field %s in node after GetNodes(tags)"%field
1005 print "Updated node", node_id
1007 def DeleteNodes(self):
1009 Delete any random nodes we may have added.
1012 for node_id in self.node_ids:
1013 # Remove from node groups
1014 node = self.api.GetNodes([node_id])[0]
1015 for node_tag in GetNodeTags ( {'node_id': node_id} ):
1016 self.api.UpdateNodeTag(node_tag['node_tag_id'],'')
1019 node = self.api.GetNodes([node_id])[0]
1020 assert not node['nodegroup_ids']
1022 self.api.DeleteNode(node_id)
1025 assert not self.api.GetNodes([node_id])
1028 print "Deleted node", node_id
1031 assert not self.api.GetNodes(self.node_ids)
1035 def AddInterfaces(self, per_node = 1):
1037 Add a number of random network interfaces to each node.
1040 network_methods = self.api.GetNetworkMethods()
1041 if not network_methods:
1042 raise Exception, "No network methods"
1044 network_types = self.api.GetNetworkTypes()
1045 if not network_types:
1046 raise Exception, "No network types"
1048 for node_id in self.node_ids:
1049 for i in range(per_node):
1050 method = random.sample(network_methods, 1)[0]
1051 type = random.sample(network_types, 1)[0]
1054 interface_fields = random_interface(method, type)
1055 interface_id = self.api.AddInterface(node_id, interface_fields)
1057 # Should return a unique interface_id
1058 assert interface_id not in self.interface_ids
1059 self.interface_ids.append(interface_id)
1063 interface = self.api.GetInterfaces([interface_id])[0]
1064 for field in interface_fields:
1065 assert interface[field] == interface_fields[field]
1068 print "Added interface", interface_id, "to node", node_id
1070 def UpdateInterfaces(self):
1072 Make random changes to any network interfaces we may have added.
1075 network_methods = self.api.GetNetworkMethods()
1076 if not network_methods:
1077 raise Exception, "No network methods"
1079 network_types = self.api.GetNetworkTypes()
1080 if not network_types:
1081 raise Exception, "No network types"
1083 for interface_id in self.interface_ids:
1084 method = random.sample(network_methods, 1)[0]
1085 type = random.sample(network_types, 1)[0]
1088 interface_fields = random_interface(method, type)
1089 self.api.UpdateInterface(interface_id, interface_fields)
1093 interface = self.api.GetInterfaces([interface_id])[0]
1094 for field in interface_fields:
1095 assert interface[field] == interface_fields[field]
1098 print "Updated interface", interface_id
1100 def DeleteInterfaces(self):
1102 Delete any random network interfaces we may have added.
1105 for interface_id in self.interface_ids:
1106 self.api.DeleteInterface(interface_id)
1109 assert not self.api.GetInterfaces([interface_id])
1112 print "Deleted interface", interface_id
1115 assert not self.api.GetInterfaces(self.interface_ids)
1117 self.interface_ids = []
1119 def AddIlinks (self, n):
1121 Add random links between interfaces.
1125 src = random.sample(self.interface_ids,1)[0]
1126 dst = random.sample(self.interface_ids,1)[0]
1127 ilink_id = self.api.AddIlink (src,dst,
1128 self.ilink_type_ids[i],
1131 assert ilink_id not in self.ilink_ids
1132 self.ilink_ids.append(ilink_id)
1135 print 'Added Ilink',ilink_id,' - attached interface',src,'to',dst
1138 retrieve=GetIlinks({'src_interface_id':src,'dst_interface_id':dst,
1139 'tag_type_id':self.ilink_type_ids[i]})
1140 assert ilink_id==retrieve[0]['ilink_id']
1143 def UpdateIlinks (self):
1145 for ilink_id in self.ilink_ids:
1146 new_value=random_ilink()
1147 self.api.UpdateIlink(ilink_id,new_value)
1150 ilink=self.api.GetIlinks([ilink_id])[0]
1151 assert ilink['value'] == new_value
1154 print 'Updated Ilink',ilink_id
1156 def DeleteIlinks (self):
1157 for ilink_id in self.ilink_ids:
1158 self.api.DeleteIlink(ilink_id)
1161 assert not self.api.GetIlinks({'ilink_id':ilink_id})
1164 print 'Deleted Ilink',ilink_id
1167 assert not self.api.GetIlinks(self.ilink_ids)
1172 def AddPCUs(self, per_site = 1):
1174 Add a number of random PCUs to each site. Each node at the
1175 site will be added to a port on the PCU if AddNodes() was
1179 for site_id in self.site_ids:
1180 for i in range(per_site):
1182 pcu_fields = random_pcu()
1183 pcu_id = self.api.AddPCU(site_id, pcu_fields)
1185 # Should return a unique pcu_id
1186 assert pcu_id not in self.pcu_ids
1187 self.pcu_ids.append(pcu_id)
1189 # Add each node at this site to a different port on this PCU
1190 site = self.api.GetSites([site_id])[0]
1191 port = randint(1, 10)
1192 for node_id in site['node_ids']:
1193 self.api.AddNodeToPCU(node_id, pcu_id, port)
1198 pcu = self.api.GetPCUs([pcu_id])[0]
1199 for field in pcu_fields:
1200 assert pcu[field] == pcu_fields[field]
1203 print "Added PCU", pcu_id, "to site", site_id
1205 def UpdatePCUs(self):
1207 Make random changes to any PCUs we may have added.
1210 for pcu_id in self.pcu_ids:
1212 pcu_fields = random_pcu()
1213 self.api.UpdatePCU(pcu_id, pcu_fields)
1217 pcu = self.api.GetPCUs([pcu_id])[0]
1218 for field in pcu_fields:
1219 assert pcu[field] == pcu_fields[field]
1222 print "Updated PCU", pcu_id
1224 def DeletePCUs(self):
1226 Delete any random nodes we may have added.
1229 for pcu_id in self.pcu_ids:
1230 # Remove nodes from PCU
1231 pcu = self.api.GetPCUs([pcu_id])[0]
1232 for node_id in pcu['node_ids']:
1233 self.api.DeleteNodeFromPCU(node_id, pcu_id)
1236 pcu = self.api.GetPCUs([pcu_id])[0]
1237 assert not pcu['node_ids']
1239 self.api.DeletePCU(pcu_id)
1242 assert not self.api.GetPCUs([pcu_id])
1245 print "Deleted PCU", pcu_id
1248 assert not self.api.GetPCUs(self.pcu_ids)
1252 def AddConfFiles(self, n = 10):
1254 Add a number of random global configuration files.
1260 # Add a random configuration file
1261 conf_files.append(random_conf_file())
1264 # Add a nodegroup override file
1265 nodegroup_conf_file = conf_files[0].copy()
1266 nodegroup_conf_file['source'] = randpath(255)
1267 conf_files.append(nodegroup_conf_file)
1269 # Add a node override file
1270 node_conf_file = conf_files[0].copy()
1271 node_conf_file['source'] = randpath(255)
1272 conf_files.append(node_conf_file)
1274 for conf_file_fields in conf_files:
1275 conf_file_id = self.api.AddConfFile(conf_file_fields)
1277 # Should return a unique conf_file_id
1278 assert conf_file_id not in self.conf_file_ids
1279 self.conf_file_ids.append(conf_file_id)
1282 if conf_file_fields == nodegroup_conf_file and self.nodegroup_ids:
1283 nodegroup_id = random.sample(self.nodegroup_ids, 1)[0]
1284 self.api.AddConfFileToNodeGroup(conf_file_id, nodegroup_id)
1289 if conf_file_fields == node_conf_file and self.node_ids:
1290 node_id = random.sample(self.node_ids, 1)[0]
1291 self.api.AddConfFileToNode(conf_file_id, node_id)
1296 # Check configuration file
1297 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1298 for field in conf_file_fields:
1299 assert conf_file[field] == conf_file_fields[field]
1302 print "Added configuration file", conf_file_id,
1303 if nodegroup_id is not None:
1304 print "to node group", nodegroup_id,
1305 elif node_id is not None:
1306 print "to node", node_id,
1309 def UpdateConfFiles(self):
1311 Make random changes to any configuration files we may have added.
1314 for conf_file_id in self.conf_file_ids:
1315 # Update configuration file
1316 conf_file_fields = random_conf_file()
1317 # Do not update dest so that it remains an override if set
1318 if 'dest' in conf_file_fields:
1319 del conf_file_fields['dest']
1320 self.api.UpdateConfFile(conf_file_id, conf_file_fields)
1323 # Check configuration file
1324 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1325 for field in conf_file_fields:
1326 assert conf_file[field] == conf_file_fields[field]
1329 print "Updated configuration file", conf_file_id
1331 def DeleteConfFiles(self):
1333 Delete any random configuration files we may have added.
1336 for conf_file_id in self.conf_file_ids:
1337 self.api.DeleteConfFile(conf_file_id)
1340 assert not self.api.GetConfFiles([conf_file_id])
1343 print "Deleted configuration file", conf_file_id
1346 assert not self.api.GetConfFiles(self.conf_file_ids)
1348 self.conf_file_ids = []
1350 def AddTagTypes(self,n_sa,n_ng,n_il):
1352 Add as many tag types as there are nodegroups,
1353 will use value=yes for each nodegroup
1356 roles = self.api.GetRoles()
1358 raise Exception, "No roles"
1359 role_ids = [role['role_id'] for role in roles]
1361 for i in range (n_sa + n_ng + n_il):
1362 tag_type_fields = random_tag_type (role_ids)
1363 tag_type_id = self.api.AddTagType (tag_type_fields)
1365 assert tag_type_id not in \
1366 self.slice_type_ids + \
1367 self.nodegroup_type_ids + \
1371 self.slice_type_ids.append(tag_type_id)
1372 elif i < n_sa+n_ng :
1373 self.nodegroup_type_ids.append(tag_type_id)
1375 self.ilink_type_ids.append(tag_type_id)
1378 tag_type = self.api.GetTagTypes([tag_type_id])[0]
1379 for field in tag_type_fields:
1380 assert tag_type[field] == tag_type_fields[field]
1382 print "Updated slice attribute type", tag_type_id
1384 def UpdateTagTypes(self):
1386 Make random changes to any slice attribute types we may have added.
1389 roles = self.api.GetRoles()
1391 raise Exception, "No roles"
1392 role_ids = [role['role_id'] for role in roles]
1394 for tag_type_id in self.slice_type_ids + self.nodegroup_type_ids + self.ilink_type_ids:
1395 # Update slice attribute type
1396 tag_type_fields = random_tag_type(role_ids)
1397 self.api.UpdateTagType(tag_type_id, tag_type_fields)
1400 # Check slice attribute type
1401 tag_type = self.api.GetTagTypes([tag_type_id])[0]
1402 for field in tag_type_fields:
1403 assert tag_type[field] == tag_type_fields[field]
1405 print "Updated slice attribute type", tag_type_id
1407 def DeleteTagTypes(self):
1409 Delete any random slice attribute types we may have added.
1412 for tag_type_id in self.slice_type_ids + self.nodegroup_type_ids + self.ilink_type_ids:
1413 self.api.DeleteTagType(tag_type_id)
1416 assert not self.api.GetTagTypes([tag_type_id])
1419 print "Deleted slice attribute type", tag_type_id
1422 assert not self.api.GetTagTypes(self.slice_type_ids+self.nodegroup_type_ids+self.ilink_type_ids)
1424 self.slice_type_ids = []
1425 self.nodegroup_type_ids = []
1427 def AddSlices(self, per_site = 10):
1429 Add a number of random slices per site.
1432 for site in self.api.GetSites(self.site_ids):
1433 for i in range(min(per_site, site['max_slices'])):
1435 slice_fields = random_slice(site['login_base'])
1436 slice_id = self.api.AddSlice(slice_fields)
1438 # Should return a unique slice_id
1439 assert slice_id not in self.slice_ids
1440 self.slice_ids.append(slice_id)
1442 # Add slice to a random set of nodes
1443 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1445 self.api.AddSliceToNodes(slice_id, node_ids)
1447 # Add random set of site users to slice
1448 person_ids = random.sample(site['person_ids'], randint(0, len(site['person_ids'])))
1449 for person_id in person_ids:
1450 self.api.AddPersonToSlice(person_id, slice_id)
1454 slice = self.api.GetSlices([slice_id])[0]
1455 for field in slice_fields:
1456 assert slice[field] == slice_fields[field]
1458 assert set(node_ids) == set(slice['node_ids'])
1459 assert set(person_ids) == set(slice['person_ids'])
1462 print "Added slice", slice_id, "to site", site['site_id'],
1464 print "and nodes", node_ids,
1467 print "Added users", site['person_ids'], "to slice", slice_id
1469 def UpdateSlices(self):
1471 Make random changes to any slices we may have added.
1474 for slice_id in self.slice_ids:
1476 slice_fields = random_slice("unused")
1477 # Cannot change slice name
1478 if 'name' in slice_fields:
1479 del slice_fields['name']
1480 self.api.UpdateSlice(slice_id, slice_fields)
1482 slice = self.api.GetSlices([slice_id])[0]
1484 # Add slice to a random set of nodes
1485 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1486 self.api.AddSliceToNodes(slice_id, list(set(node_ids) - set(slice['node_ids'])))
1487 self.api.DeleteSliceFromNodes(slice_id, list(set(slice['node_ids']) - set(node_ids)))
1489 # Add random set of users to slice
1490 person_ids = random.sample(self.person_ids, randint(0, len(self.person_ids)))
1491 for person_id in (set(person_ids) - set(slice['person_ids'])):
1492 self.api.AddPersonToSlice(person_id, slice_id)
1493 for person_id in (set(slice['person_ids']) - set(person_ids)):
1494 self.api.DeletePersonFromSlice(person_id, slice_id)
1497 slice = self.api.GetSlices([slice_id])[0]
1498 for field in slice_fields:
1499 assert slice[field] == slice_fields[field]
1500 assert set(node_ids) == set(slice['node_ids'])
1501 assert set(person_ids) == set(slice['person_ids'])
1504 print "Updated slice", slice_id
1505 print "Added nodes", node_ids, "to slice", slice_id
1506 print "Added persons", person_ids, "to slice", slice_id
1508 def DeleteSlices(self):
1510 Delete any random slices we may have added.
1513 for slice_id in self.slice_ids:
1514 self.api.DeleteSlice(slice_id)
1517 assert not self.api.GetSlices([slice_id])
1520 print "Deleted slice", slice_id
1523 assert not self.api.GetSlices(self.slice_ids)
1527 def AddSliceTags(self, per_slice = 2):
1529 Add a number of random slices per site.
1532 if not self.slice_type_ids:
1535 for slice_id in self.slice_ids:
1536 slice = self.api.GetSlices([slice_id])[0]
1538 for i in range(per_slice):
1539 # Set a random slice/sliver attribute
1540 for tag_type_id in random.sample(self.slice_type_ids, 1):
1541 value = randstr(16, letters + '_' + digits)
1542 # Make it a sliver attribute with 50% probability
1543 if slice['node_ids']:
1544 node_id = random.sample(slice['node_ids'] + [None] * len(slice['node_ids']), 1)[0]
1548 # Add slice attribute
1550 slice_tag_id = self.api.AddSliceTag(slice_id, tag_type_id, value)
1552 slice_tag_id = self.api.AddSliceTag(slice_id, tag_type_id, value, node_id)
1554 # Should return a unique slice_tag_id
1555 assert slice_tag_id not in self.slice_tag_ids
1556 self.slice_tag_ids.append(slice_tag_id)
1559 # Check slice attribute
1560 slice_tag = self.api.GetSliceTags([slice_tag_id])[0]
1561 for field in 'tag_type_id', 'slice_id', 'node_id', 'slice_tag_id', 'value':
1562 assert slice_tag[field] == locals()[field]
1565 print "Added slice attribute", slice_tag_id, "of type", tag_type_id,
1566 if node_id is not None:
1567 print "to node", node_id,
1570 def UpdateSliceTags(self):
1572 Make random changes to any slice attributes we may have added.
1575 for slice_tag_id in self.slice_tag_ids:
1576 # Update slice attribute
1577 value = randstr(16, letters + '_' + digits)
1578 self.api.UpdateSliceTag(slice_tag_id, value)
1580 # Check slice attribute again
1581 slice_tag = self.api.GetSliceTags([slice_tag_id])[0]
1582 assert slice_tag['value'] == value
1585 print "Updated slice attribute", slice_tag_id
1587 def DeleteSliceTags(self):
1589 Delete any random slice attributes we may have added.
1592 for slice_tag_id in self.slice_tag_ids:
1593 self.api.DeleteSliceTag(slice_tag_id)
1596 assert not self.api.GetSliceTags([slice_tag_id])
1599 print "Deleted slice attribute", slice_tag_id
1602 assert not self.api.GetSliceTags(self.slice_tag_ids)
1604 self.slice_tag_ids = []
1607 parser = OptionParser()
1608 parser.add_option("-c", "--check", action = "store_true", default = False,
1609 help = "Check most actions (default: %default)")
1610 parser.add_option("-q", "--quiet", action = "store_true", default = False,
1611 help = "Be quiet (default: %default)")
1612 parser.add_option("-p","--preserve", action="store_true", default =False,
1613 help = "Do not delete created objects")
1614 parser.add_option("-t", "--tiny", action = "store_true", default = False,
1615 help = "Run a tiny test (default: %default)")
1616 parser.add_option("-s", "--short-names", action="store_true", dest="short_names", default = False,
1617 help = "Generate smaller names for checking UI rendering")
1618 (options, args) = parser.parse_args()
1620 test = Test(api = Shell(),
1621 check = options.check,
1622 verbose = not options.quiet,
1623 preserve = options.preserve)
1626 sizes = Test.sizes_tiny
1628 sizes = Test.sizes_default
1631 if options.short_names:
1632 namelengths = Test.namelengths_short
1634 namelengths = Test.namelengths_default
1638 if __name__ == "__main__":