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(128),
136 'last_name': randstr(128),
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,
273 namelengths_short = {
278 'sitename_contents':letters+digits+whitespace+punctuation,
279 'abbreviated_name':24,
280 'abbreviated_name_contents':letters+digits+whitespace+punctuation,
285 def __init__(self, api, check = True, verbose = True, preserve = False):
288 self.verbose = verbose
289 self.preserve = preserve
292 self.address_type_ids = []
293 self.address_ids = []
296 self.slice_type_ids = []
297 self.nodegroup_type_ids = []
298 self.ilink_type_ids = []
299 self.nodegroup_ids = []
301 self.interface_ids = []
304 self.conf_file_ids = []
306 self.slice_tag_ids = []
308 def Cardinals (self):
309 return [len(x) for x in (
310 self.api.GetNodes({},['node_id']),
311 self.api.GetSites({},['site_id']),
312 self.api.GetPersons({},['person_id']),
313 self.api.GetSlices({},['slice_id']),
316 def Run(self, **kwds):
318 Run a complete database and API consistency test. Populates
319 the database with a set of random entities, updates them, then
320 deletes them. Examples:
322 test.Run() # Defaults
323 test.Run(**Test.sizes_default) # Defaults
324 test.Run(**Test.sizes_tiny) # Tiny set
325 test.Run(sites = 123, slices_per_site = 4) # Defaults with overrides
328 cardinals_before=self.Cardinals()
329 print 'Cardinals before test (n,s,p,sl)',cardinals_before
334 print 'Preserving - delete skipped'
338 cardinals_after=self.Cardinals()
339 print 'Cardinals after test (n,s,p,sl)',cardinals_after
341 if cardinals_before != cardinals_after:
342 raise Exception, 'cardinals before and after differ - check deletion mechanisms'
344 def Add(self, **kwds):
346 Populate the database with a set of random entities. Examples:
351 sizes = self.sizes_default.copy()
354 self.AddSites(sizes['sites'])
355 self.AddAddressTypes(sizes['address_types'])
356 self.AddAddresses(sizes['addresses_per_site'])
357 self.AddPersons(sizes['persons_per_site'])
358 self.AddKeys(sizes['keys_per_person'])
359 self.AddTagTypes(sizes['slice_tags'],sizes['nodegroups'],sizes['ilinks'])
360 self.AddNodeGroups(sizes['nodegroups'])
361 self.AddNodes(sizes['nodes_per_site'])
362 self.AddInterfaces(sizes['interfaces_per_node'])
363 self.AddIlinks (sizes['ilinks'])
364 self.AddPCUs(sizes['pcus_per_site'])
365 self.AddConfFiles(sizes['conf_files'])
366 self.AddSlices(sizes['slices_per_site'])
367 self.AddSliceTags(sizes['attributes_per_slice'])
371 self.UpdateAddressTypes()
372 self.UpdateAddresses()
375 self.UpdateTagTypes()
376 self.UpdateNodeGroups()
378 self.UpdateInterfaces()
381 self.UpdateConfFiles()
383 self.UpdateSliceTags()
386 self.DeleteSliceTags()
389 self.DeleteConfFiles()
392 self.DeleteInterfaces()
395 self.DeleteNodeGroups()
396 self.DeleteTagTypes()
397 self.DeleteAddresses()
398 self.DeleteAddressTypes()
401 def AddSites(self, n = 10):
403 Add a number of random sites.
408 site_fields = random_site()
409 site_id = self.api.AddSite(site_fields)
411 # Should return a unique site_id
412 assert site_id not in self.site_ids
413 self.site_ids.append(site_id)
415 # Enable slice creation
416 site_fields['max_slices'] = randint(1, 10)
417 self.api.UpdateSite(site_id, site_fields)
421 site = self.api.GetSites([site_id])[0]
422 for field in site_fields:
423 assert site[field] == site_fields[field]
426 print "Added site", site_id
428 def UpdateSites(self):
430 Make random changes to any sites we may have added.
433 for site_id in self.site_ids:
435 site_fields = random_site()
436 # Do not change login_base
437 if 'login_base' in site_fields:
438 del site_fields['login_base']
439 self.api.UpdateSite(site_id, site_fields)
443 site = self.api.GetSites([site_id])[0]
444 for field in site_fields:
445 assert site[field] == site_fields[field]
448 print "Updated site", site_id
450 def DeleteSites(self):
452 Delete any random sites we may have added.
455 for site_id in self.site_ids:
456 self.api.DeleteSite(site_id)
459 assert not self.api.GetSites([site_id])
462 print "Deleted site", site_id
465 assert not self.api.GetSites(self.site_ids)
469 def AddAddressTypes(self, n = 2):
471 Add a number of random address types.
475 address_type_fields = random_address_type()
476 address_type_id = self.api.AddAddressType(address_type_fields)
478 # Should return a unique address_type_id
479 assert address_type_id not in self.address_type_ids
480 self.address_type_ids.append(address_type_id)
484 address_type = self.api.GetAddressTypes([address_type_id])[0]
485 for field in address_type_fields:
486 assert address_type[field] == address_type_fields[field]
489 print "Added address type", address_type_id
491 def UpdateAddressTypes(self):
493 Make random changes to any address types we may have added.
496 for address_type_id in self.address_type_ids:
497 # Update address_type
498 address_type_fields = random_address_type()
499 self.api.UpdateAddressType(address_type_id, address_type_fields)
503 address_type = self.api.GetAddressTypes([address_type_id])[0]
504 for field in address_type_fields:
505 assert address_type[field] == address_type_fields[field]
508 print "Updated address_type", address_type_id
510 def DeleteAddressTypes(self):
512 Delete any random address types we may have added.
515 for address_type_id in self.address_type_ids:
516 self.api.DeleteAddressType(address_type_id)
519 assert not self.api.GetAddressTypes([address_type_id])
522 print "Deleted address type", address_type_id
525 assert not self.api.GetAddressTypes(self.address_type_ids)
527 self.address_type_ids = []
529 def AddAddresses(self, per_site = 2):
531 Add a number of random addresses to each site.
534 for site_id in self.site_ids:
535 for i in range(per_site):
536 address_fields = random_address()
537 address_id = self.api.AddSiteAddress(site_id, address_fields)
539 # Should return a unique address_id
540 assert address_id not in self.address_ids
541 self.address_ids.append(address_id)
543 # Add random address type
544 if self.address_type_ids:
545 for address_type_id in random.sample(self.address_type_ids, 1):
546 self.api.AddAddressTypeToAddress(address_type_id, address_id)
550 address = self.api.GetAddresses([address_id])[0]
551 for field in address_fields:
552 assert address[field] == address_fields[field]
555 print "Added address", address_id, "to site", site_id
557 def UpdateAddresses(self):
559 Make random changes to any addresses we may have added.
562 for address_id in self.address_ids:
564 address_fields = random_address()
565 self.api.UpdateAddress(address_id, address_fields)
569 address = self.api.GetAddresses([address_id])[0]
570 for field in address_fields:
571 assert address[field] == address_fields[field]
574 print "Updated address", address_id
576 def DeleteAddresses(self):
578 Delete any random addresses we may have added.
581 for address_id in self.address_ids:
582 # Remove address types
583 address = self.api.GetAddresses([address_id])[0]
584 for address_type_id in address['address_type_ids']:
585 self.api.DeleteAddressTypeFromAddress(address_type_id, address_id)
588 address = self.api.GetAddresses([address_id])[0]
589 assert not address['address_type_ids']
591 self.api.DeleteAddress(address_id)
594 assert not self.api.GetAddresses([address_id])
597 print "Deleted address", address_id
600 assert not self.api.GetAddresses(self.address_ids)
602 self.address_ids = []
604 def AddPersons(self, per_site = 10):
606 Add a number of random users to each site.
609 for site_id in self.site_ids:
610 for i in range(per_site):
612 person_fields = random_person()
613 person_id = self.api.AddPerson(person_fields)
615 # Should return a unique person_id
616 assert person_id not in self.person_ids
617 self.person_ids.append(person_id)
621 person = self.api.GetPersons([person_id])[0]
622 for field in person_fields:
623 if field != 'password':
624 assert person[field] == person_fields[field]
626 auth = {'AuthMethod': "password",
627 'Username': person_fields['email'],
628 'AuthString': person_fields['password']}
631 # Check that user is disabled
633 assert not self.api.AuthCheck(auth)
637 # Add random set of roles
638 role_ids = random.sample([20, 30, 40], randint(1, 3))
639 for role_id in role_ids:
640 self.api.AddRoleToPerson(role_id, person_id)
643 person = self.api.GetPersons([person_id])[0]
644 assert set(role_ids) == set(person['role_ids'])
647 self.api.UpdatePerson(person_id, {'enabled': True})
650 # Check that user is enabled
651 assert self.api.AuthCheck(auth)
653 # Associate user with site
654 self.api.AddPersonToSite(person_id, site_id)
655 self.api.SetPersonPrimarySite(person_id, site_id)
658 person = self.api.GetPersons([person_id])[0]
659 assert person['site_ids'][0] == site_id
662 print "Added user", person_id, "to site", site_id
664 def UpdatePersons(self):
666 Make random changes to any users we may have added.
669 for person_id in self.person_ids:
671 person_fields = random_person()
673 person_fields['enabled'] = True
674 self.api.UpdatePerson(person_id, person_fields)
678 person = self.api.GetPersons([person_id])[0]
679 for field in person_fields:
680 if field != 'password':
681 assert person[field] == person_fields[field]
684 print "Updated person", person_id
686 person = self.api.GetPersons([person_id])[0]
688 # Associate user with a random set of sites
689 site_ids = random.sample(self.site_ids, randint(0, len(self.site_ids)))
690 for site_id in (set(site_ids) - set(person['site_ids'])):
691 self.api.AddPersonToSite(person_id, site_id)
692 for site_id in (set(person['site_ids']) - set(site_ids)):
693 self.api.DeletePersonFromSite(person_id, site_id)
696 self.api.SetPersonPrimarySite(person_id, site_ids[0])
699 person = self.api.GetPersons([person_id])[0]
700 assert set(site_ids) == set(person['site_ids'])
703 print "Updated person", person_id, "to sites", site_ids
705 def DeletePersons(self):
707 Delete any random users we may have added.
710 for person_id in self.person_ids:
712 person = self.api.GetPersons([person_id])[0]
713 for site_id in person['site_ids']:
714 self.api.DeletePersonFromSite(person_id, site_id)
717 person = self.api.GetPersons([person_id])[0]
718 assert not person['site_ids']
721 for role_id in person['role_ids']:
722 self.api.DeleteRoleFromPerson(role_id, person_id)
725 person = self.api.GetPersons([person_id])[0]
726 assert not person['role_ids']
729 self.api.UpdatePerson(person_id, {'enabled': False})
732 person = self.api.GetPersons([person_id])[0]
733 assert not person['enabled']
736 self.api.DeletePerson(person_id)
739 assert not self.api.GetPersons([person_id])
742 print "Deleted user", person_id
745 assert not self.api.GetPersons(self.person_ids)
749 def AddKeys(self, per_person = 2):
751 Add a number of random keys to each user.
754 key_types = self.api.GetKeyTypes()
756 raise Exception, "No key types"
758 for person_id in self.person_ids:
759 for i in range(per_person):
761 key_fields = random_key(key_types)
762 key_id = self.api.AddPersonKey(person_id, key_fields)
764 # Should return a unique key_id
765 assert key_id not in self.key_ids
766 self.key_ids.append(key_id)
770 key = self.api.GetKeys([key_id])[0]
771 for field in key_fields:
772 assert key[field] == key_fields[field]
774 # Add and immediately blacklist a key
775 key_fields = random_key(key_types)
776 key_id = self.api.AddPersonKey(person_id, key_fields)
778 self.api.BlacklistKey(key_id)
780 # Is effectively deleted
781 assert not self.api.GetKeys([key_id])
783 # Cannot be added again
785 key_id = self.api.AddPersonKey(person_id, key_fields)
791 print "Added key", key_id, "to user", person_id
793 def UpdateKeys(self):
795 Make random changes to any keys we may have added.
798 key_types = self.api.GetKeyTypes()
800 raise Exception, "No key types"
802 for key_id in self.key_ids:
804 key_fields = random_key(key_types)
805 self.api.UpdateKey(key_id, key_fields)
809 key = self.api.GetKeys([key_id])[0]
810 for field in key_fields:
811 assert key[field] == key_fields[field]
814 print "Updated key", key_id
816 def DeleteKeys(self):
818 Delete any random keys we may have added.
821 for key_id in self.key_ids:
822 self.api.DeleteKey(key_id)
825 assert not self.api.GetKeys([key_id])
828 print "Deleted key", key_id
831 assert not self.api.GetKeys(self.key_ids)
835 def AddNodeGroups(self, n = 10):
837 Add a number of random node groups.
842 tag_type_id = self.nodegroup_type_ids[i]
843 tagname=self.api.GetTagTypes([tag_type_id])[0]['tagname']
846 groupname = random_nodegroup() ['groupname']
848 nodegroup_id = self.api.AddNodeGroup(groupname, tagname, value)
850 # Should return a unique nodegroup_id
851 assert nodegroup_id not in self.nodegroup_ids
852 self.nodegroup_ids.append(nodegroup_id)
856 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
857 assert nodegroup['groupname'] == groupname
858 assert nodegroup['tagname'] == tagname
859 assert nodegroup['value'] == value
862 print "Added node group", nodegroup_id
864 def UpdateNodeGroups(self):
866 Make random changes to any node groups we may have added.
869 for nodegroup_id in self.nodegroup_ids:
871 groupname = random_nodegroup()['groupname']
872 # cannot change tagname
873 nodegroup_fields = { 'groupname':groupname }
874 self.api.UpdateNodeGroup(nodegroup_id, nodegroup_fields)
878 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
879 for field in nodegroup_fields:
880 assert nodegroup[field] == nodegroup_fields[field]
883 print "Updated node group", nodegroup_id
885 def DeleteNodeGroups(self):
887 Delete any random node groups we may have added.
890 for nodegroup_id in self.nodegroup_ids:
891 self.api.DeleteNodeGroup(nodegroup_id)
894 assert not self.api.GetNodeGroups([nodegroup_id])
897 print "Deleted node group", nodegroup_id
900 assert not self.api.GetNodeGroups(self.nodegroup_ids)
902 self.nodegroup_ids = []
904 def AddNodes(self, per_site = 2):
906 Add a number of random nodes to each site. Each node will also
907 be added to a random node group if AddNodeGroups() was
911 node_types = self.api.GetNodeTypes()
913 raise Exception, "No node types"
914 boot_states = self.api.GetBootStates()
916 raise Exception, "No boot states"
918 for site_id in self.site_ids:
919 for i in range(per_site):
921 node_fields = random_node(node_types,boot_states)
922 node_id = self.api.AddNode(site_id, node_fields)
924 # Should return a unique node_id
925 assert node_id not in self.node_ids
926 self.node_ids.append(node_id)
928 # Add to a random set of node groups
929 nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
930 for nodegroup_id in nodegroup_ids:
931 tagname = self.api.GetNodeGroups([nodegroup_id])[0]['tagname']
932 self.api.AddNodeTag( node_id, tagname, 'yes' )
936 node = self.api.GetNodes([node_id])[0]
937 for field in node_fields:
938 if field not in tag_fields:
939 assert node[field] == node_fields[field]
942 print "Added node", node_id
944 def UpdateNodes(self):
946 Make random changes to any nodes we may have added.
949 node_types = self.api.GetNodeTypes()
951 raise Exception, "No node types"
952 boot_states = self.api.GetBootStates()
954 raise Exception, "No boot states"
956 for node_id in self.node_ids:
958 node_fields = random_node(node_types,boot_states)
959 self.api.UpdateNode(node_id, node_fields)
961 node = self.api.GetNodes([node_id])[0]
963 # Add to a random set of node groups
964 nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
965 for nodegroup_id in (set(nodegroup_ids) - set(node['nodegroup_ids'])):
966 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
967 tagname = nodegroup['tagname']
968 node_tags = self.api.GetNodeTags({'node_id':node_id,'tagname':tagname})
970 self.api.AddNodeTag(node_id,tagname,'yes')
972 node_tag=node_tags[0]
973 self.api.UpdateNodeTag(node_tag['node_tag_id'],'yes')
974 for nodegroup_id in (set(node['nodegroup_ids']) - set(nodegroup_ids)):
975 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
976 tagname = nodegroup['tagname']
977 node_tags = self.api.GetNodeTags({'node_id':node_id,'tagname':tagname})
979 self.api.AddNodeTag(node_id,tagname,'no')
981 node_tag=node_tags[0]
982 self.api.UpdateNodeTag(node_tag['node_tag_id'],'no')
986 node = self.api.GetNodes([node_id])[0]
987 for field in node_fields:
988 if field not in tag_fields:
989 if node[field] != node_fields[field]:
990 raise Exception, "Unexpected field %s in node after GetNodes()"%field
991 assert set(nodegroup_ids) == set(node['nodegroup_ids'])
993 print 'WARNING: skipping updatenode with tags as this is not implemented yet'
994 # again when fetching 'arch' explicitly
995 node2 = self.api.GetNodes([node_id],node_fields.keys())[0]
996 for field in node_fields:
997 if node2[field] != node_fields[field]:
998 raise Exception, "Unexpected field %s in node after GetNodes(tags)"%field
1001 print "Updated node", node_id
1003 def DeleteNodes(self):
1005 Delete any random nodes we may have added.
1008 for node_id in self.node_ids:
1009 # Remove from node groups
1010 node = self.api.GetNodes([node_id])[0]
1011 for node_tag in GetNodeTags ( {'node_id': node_id} ):
1012 self.api.UpdateNodeTag(node_tag['node_tag_id'],'')
1015 node = self.api.GetNodes([node_id])[0]
1016 assert not node['nodegroup_ids']
1018 self.api.DeleteNode(node_id)
1021 assert not self.api.GetNodes([node_id])
1024 print "Deleted node", node_id
1027 assert not self.api.GetNodes(self.node_ids)
1031 def AddInterfaces(self, per_node = 1):
1033 Add a number of random network interfaces to each node.
1036 network_methods = self.api.GetNetworkMethods()
1037 if not network_methods:
1038 raise Exception, "No network methods"
1040 network_types = self.api.GetNetworkTypes()
1041 if not network_types:
1042 raise Exception, "No network types"
1044 for node_id in self.node_ids:
1045 for i in range(per_node):
1046 method = random.sample(network_methods, 1)[0]
1047 type = random.sample(network_types, 1)[0]
1050 interface_fields = random_interface(method, type)
1051 interface_id = self.api.AddInterface(node_id, interface_fields)
1053 # Should return a unique interface_id
1054 assert interface_id not in self.interface_ids
1055 self.interface_ids.append(interface_id)
1059 interface = self.api.GetInterfaces([interface_id])[0]
1060 for field in interface_fields:
1061 assert interface[field] == interface_fields[field]
1064 print "Added interface", interface_id, "to node", node_id
1066 def UpdateInterfaces(self):
1068 Make random changes to any network interfaces we may have added.
1071 network_methods = self.api.GetNetworkMethods()
1072 if not network_methods:
1073 raise Exception, "No network methods"
1075 network_types = self.api.GetNetworkTypes()
1076 if not network_types:
1077 raise Exception, "No network types"
1079 for interface_id in self.interface_ids:
1080 method = random.sample(network_methods, 1)[0]
1081 type = random.sample(network_types, 1)[0]
1084 interface_fields = random_interface(method, type)
1085 self.api.UpdateInterface(interface_id, interface_fields)
1089 interface = self.api.GetInterfaces([interface_id])[0]
1090 for field in interface_fields:
1091 assert interface[field] == interface_fields[field]
1094 print "Updated interface", interface_id
1096 def DeleteInterfaces(self):
1098 Delete any random network interfaces we may have added.
1101 for interface_id in self.interface_ids:
1102 self.api.DeleteInterface(interface_id)
1105 assert not self.api.GetInterfaces([interface_id])
1108 print "Deleted interface", interface_id
1111 assert not self.api.GetInterfaces(self.interface_ids)
1113 self.interface_ids = []
1115 def AddIlinks (self, n):
1117 Add random links between interfaces.
1121 src = random.sample(self.interface_ids,1)[0]
1122 dst = random.sample(self.interface_ids,1)[0]
1123 ilink_id = self.api.AddIlink (src,dst,
1124 self.ilink_type_ids[i],
1127 assert ilink_id not in self.ilink_ids
1128 self.ilink_ids.append(ilink_id)
1131 print 'Added Ilink',ilink_id,' - attached interface',src,'to',dst
1134 retrieve=GetIlinks({'src_interface_id':src,'dst_interface_id':dst,
1135 'tag_type_id':self.ilink_type_ids[i]})
1136 assert ilink_id==retrieve[0]['ilink_id']
1139 def UpdateIlinks (self):
1141 for ilink_id in self.ilink_ids:
1142 new_value=random_ilink()
1143 self.api.UpdateIlink(ilink_id,new_value)
1146 ilink=self.api.GetIlinks([ilink_id])[0]
1147 assert ilink['value'] == new_value
1150 print 'Updated Ilink',ilink_id
1152 def DeleteIlinks (self):
1153 for ilink_id in self.ilink_ids:
1154 self.api.DeleteIlink(ilink_id)
1157 assert not self.api.GetIlinks({'ilink_id':ilink_id})
1160 print 'Deleted Ilink',ilink_id
1163 assert not self.api.GetIlinks(self.ilink_ids)
1168 def AddPCUs(self, per_site = 1):
1170 Add a number of random PCUs to each site. Each node at the
1171 site will be added to a port on the PCU if AddNodes() was
1175 for site_id in self.site_ids:
1176 for i in range(per_site):
1178 pcu_fields = random_pcu()
1179 pcu_id = self.api.AddPCU(site_id, pcu_fields)
1181 # Should return a unique pcu_id
1182 assert pcu_id not in self.pcu_ids
1183 self.pcu_ids.append(pcu_id)
1185 # Add each node at this site to a different port on this PCU
1186 site = self.api.GetSites([site_id])[0]
1187 port = randint(1, 10)
1188 for node_id in site['node_ids']:
1189 self.api.AddNodeToPCU(node_id, pcu_id, port)
1194 pcu = self.api.GetPCUs([pcu_id])[0]
1195 for field in pcu_fields:
1196 assert pcu[field] == pcu_fields[field]
1199 print "Added PCU", pcu_id, "to site", site_id
1201 def UpdatePCUs(self):
1203 Make random changes to any PCUs we may have added.
1206 for pcu_id in self.pcu_ids:
1208 pcu_fields = random_pcu()
1209 self.api.UpdatePCU(pcu_id, pcu_fields)
1213 pcu = self.api.GetPCUs([pcu_id])[0]
1214 for field in pcu_fields:
1215 assert pcu[field] == pcu_fields[field]
1218 print "Updated PCU", pcu_id
1220 def DeletePCUs(self):
1222 Delete any random nodes we may have added.
1225 for pcu_id in self.pcu_ids:
1226 # Remove nodes from PCU
1227 pcu = self.api.GetPCUs([pcu_id])[0]
1228 for node_id in pcu['node_ids']:
1229 self.api.DeleteNodeFromPCU(node_id, pcu_id)
1232 pcu = self.api.GetPCUs([pcu_id])[0]
1233 assert not pcu['node_ids']
1235 self.api.DeletePCU(pcu_id)
1238 assert not self.api.GetPCUs([pcu_id])
1241 print "Deleted PCU", pcu_id
1244 assert not self.api.GetPCUs(self.pcu_ids)
1248 def AddConfFiles(self, n = 10):
1250 Add a number of random global configuration files.
1256 # Add a random configuration file
1257 conf_files.append(random_conf_file())
1260 # Add a nodegroup override file
1261 nodegroup_conf_file = conf_files[0].copy()
1262 nodegroup_conf_file['source'] = randpath(255)
1263 conf_files.append(nodegroup_conf_file)
1265 # Add a node override file
1266 node_conf_file = conf_files[0].copy()
1267 node_conf_file['source'] = randpath(255)
1268 conf_files.append(node_conf_file)
1270 for conf_file_fields in conf_files:
1271 conf_file_id = self.api.AddConfFile(conf_file_fields)
1273 # Should return a unique conf_file_id
1274 assert conf_file_id not in self.conf_file_ids
1275 self.conf_file_ids.append(conf_file_id)
1278 if conf_file_fields == nodegroup_conf_file and self.nodegroup_ids:
1279 nodegroup_id = random.sample(self.nodegroup_ids, 1)[0]
1280 self.api.AddConfFileToNodeGroup(conf_file_id, nodegroup_id)
1285 if conf_file_fields == node_conf_file and self.node_ids:
1286 node_id = random.sample(self.node_ids, 1)[0]
1287 self.api.AddConfFileToNode(conf_file_id, node_id)
1292 # Check configuration file
1293 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1294 for field in conf_file_fields:
1295 assert conf_file[field] == conf_file_fields[field]
1298 print "Added configuration file", conf_file_id,
1299 if nodegroup_id is not None:
1300 print "to node group", nodegroup_id,
1301 elif node_id is not None:
1302 print "to node", node_id,
1305 def UpdateConfFiles(self):
1307 Make random changes to any configuration files we may have added.
1310 for conf_file_id in self.conf_file_ids:
1311 # Update configuration file
1312 conf_file_fields = random_conf_file()
1313 # Do not update dest so that it remains an override if set
1314 if 'dest' in conf_file_fields:
1315 del conf_file_fields['dest']
1316 self.api.UpdateConfFile(conf_file_id, conf_file_fields)
1319 # Check configuration file
1320 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1321 for field in conf_file_fields:
1322 assert conf_file[field] == conf_file_fields[field]
1325 print "Updated configuration file", conf_file_id
1327 def DeleteConfFiles(self):
1329 Delete any random configuration files we may have added.
1332 for conf_file_id in self.conf_file_ids:
1333 self.api.DeleteConfFile(conf_file_id)
1336 assert not self.api.GetConfFiles([conf_file_id])
1339 print "Deleted configuration file", conf_file_id
1342 assert not self.api.GetConfFiles(self.conf_file_ids)
1344 self.conf_file_ids = []
1346 def AddTagTypes(self,n_sa,n_ng,n_il):
1348 Add as many tag types as there are nodegroups,
1349 will use value=yes for each nodegroup
1352 roles = self.api.GetRoles()
1354 raise Exception, "No roles"
1355 role_ids = [role['role_id'] for role in roles]
1357 for i in range (n_sa + n_ng + n_il):
1358 tag_type_fields = random_tag_type (role_ids)
1359 tag_type_id = self.api.AddTagType (tag_type_fields)
1361 assert tag_type_id not in \
1362 self.slice_type_ids + \
1363 self.nodegroup_type_ids + \
1367 self.slice_type_ids.append(tag_type_id)
1368 elif i < n_sa+n_ng :
1369 self.nodegroup_type_ids.append(tag_type_id)
1371 self.ilink_type_ids.append(tag_type_id)
1374 tag_type = self.api.GetTagTypes([tag_type_id])[0]
1375 for field in tag_type_fields:
1376 assert tag_type[field] == tag_type_fields[field]
1378 print "Updated slice attribute type", tag_type_id
1380 def UpdateTagTypes(self):
1382 Make random changes to any slice attribute types we may have added.
1385 roles = self.api.GetRoles()
1387 raise Exception, "No roles"
1388 role_ids = [role['role_id'] for role in roles]
1390 for tag_type_id in self.slice_type_ids + self.nodegroup_type_ids + self.ilink_type_ids:
1391 # Update slice attribute type
1392 tag_type_fields = random_tag_type(role_ids)
1393 self.api.UpdateTagType(tag_type_id, tag_type_fields)
1396 # Check slice attribute type
1397 tag_type = self.api.GetTagTypes([tag_type_id])[0]
1398 for field in tag_type_fields:
1399 assert tag_type[field] == tag_type_fields[field]
1401 print "Updated slice attribute type", tag_type_id
1403 def DeleteTagTypes(self):
1405 Delete any random slice attribute types we may have added.
1408 for tag_type_id in self.slice_type_ids + self.nodegroup_type_ids + self.ilink_type_ids:
1409 self.api.DeleteTagType(tag_type_id)
1412 assert not self.api.GetTagTypes([tag_type_id])
1415 print "Deleted slice attribute type", tag_type_id
1418 assert not self.api.GetTagTypes(self.slice_type_ids+self.nodegroup_type_ids+self.ilink_type_ids)
1420 self.slice_type_ids = []
1421 self.nodegroup_type_ids = []
1423 def AddSlices(self, per_site = 10):
1425 Add a number of random slices per site.
1428 for site in self.api.GetSites(self.site_ids):
1429 for i in range(min(per_site, site['max_slices'])):
1431 slice_fields = random_slice(site['login_base'])
1432 slice_id = self.api.AddSlice(slice_fields)
1434 # Should return a unique slice_id
1435 assert slice_id not in self.slice_ids
1436 self.slice_ids.append(slice_id)
1438 # Add slice to a random set of nodes
1439 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1441 self.api.AddSliceToNodes(slice_id, node_ids)
1443 # Add random set of site users to slice
1444 person_ids = random.sample(site['person_ids'], randint(0, len(site['person_ids'])))
1445 for person_id in person_ids:
1446 self.api.AddPersonToSlice(person_id, slice_id)
1450 slice = self.api.GetSlices([slice_id])[0]
1451 for field in slice_fields:
1452 assert slice[field] == slice_fields[field]
1454 assert set(node_ids) == set(slice['node_ids'])
1455 assert set(person_ids) == set(slice['person_ids'])
1458 print "Added slice", slice_id, "to site", site['site_id'],
1460 print "and nodes", node_ids,
1463 print "Added users", site['person_ids'], "to slice", slice_id
1465 def UpdateSlices(self):
1467 Make random changes to any slices we may have added.
1470 for slice_id in self.slice_ids:
1472 slice_fields = random_slice("unused")
1473 # Cannot change slice name
1474 if 'name' in slice_fields:
1475 del slice_fields['name']
1476 self.api.UpdateSlice(slice_id, slice_fields)
1478 slice = self.api.GetSlices([slice_id])[0]
1480 # Add slice to a random set of nodes
1481 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1482 self.api.AddSliceToNodes(slice_id, list(set(node_ids) - set(slice['node_ids'])))
1483 self.api.DeleteSliceFromNodes(slice_id, list(set(slice['node_ids']) - set(node_ids)))
1485 # Add random set of users to slice
1486 person_ids = random.sample(self.person_ids, randint(0, len(self.person_ids)))
1487 for person_id in (set(person_ids) - set(slice['person_ids'])):
1488 self.api.AddPersonToSlice(person_id, slice_id)
1489 for person_id in (set(slice['person_ids']) - set(person_ids)):
1490 self.api.DeletePersonFromSlice(person_id, slice_id)
1493 slice = self.api.GetSlices([slice_id])[0]
1494 for field in slice_fields:
1495 assert slice[field] == slice_fields[field]
1496 assert set(node_ids) == set(slice['node_ids'])
1497 assert set(person_ids) == set(slice['person_ids'])
1500 print "Updated slice", slice_id
1501 print "Added nodes", node_ids, "to slice", slice_id
1502 print "Added persons", person_ids, "to slice", slice_id
1504 def DeleteSlices(self):
1506 Delete any random slices we may have added.
1509 for slice_id in self.slice_ids:
1510 self.api.DeleteSlice(slice_id)
1513 assert not self.api.GetSlices([slice_id])
1516 print "Deleted slice", slice_id
1519 assert not self.api.GetSlices(self.slice_ids)
1523 def AddSliceTags(self, per_slice = 2):
1525 Add a number of random slices per site.
1528 if not self.slice_type_ids:
1531 for slice_id in self.slice_ids:
1532 slice = self.api.GetSlices([slice_id])[0]
1534 for i in range(per_slice):
1535 # Set a random slice/sliver attribute
1536 for tag_type_id in random.sample(self.slice_type_ids, 1):
1537 value = randstr(16, letters + '_' + digits)
1538 # Make it a sliver attribute with 50% probability
1539 if slice['node_ids']:
1540 node_id = random.sample(slice['node_ids'] + [None] * len(slice['node_ids']), 1)[0]
1544 # Add slice attribute
1546 slice_tag_id = self.api.AddSliceTag(slice_id, tag_type_id, value)
1548 slice_tag_id = self.api.AddSliceTag(slice_id, tag_type_id, value, node_id)
1550 # Should return a unique slice_tag_id
1551 assert slice_tag_id not in self.slice_tag_ids
1552 self.slice_tag_ids.append(slice_tag_id)
1555 # Check slice attribute
1556 slice_tag = self.api.GetSliceTags([slice_tag_id])[0]
1557 for field in 'tag_type_id', 'slice_id', 'node_id', 'slice_tag_id', 'value':
1558 assert slice_tag[field] == locals()[field]
1561 print "Added slice attribute", slice_tag_id, "of type", tag_type_id,
1562 if node_id is not None:
1563 print "to node", node_id,
1566 def UpdateSliceTags(self):
1568 Make random changes to any slice attributes we may have added.
1571 for slice_tag_id in self.slice_tag_ids:
1572 # Update slice attribute
1573 value = randstr(16, letters + '_' + digits)
1574 self.api.UpdateSliceTag(slice_tag_id, value)
1576 # Check slice attribute again
1577 slice_tag = self.api.GetSliceTags([slice_tag_id])[0]
1578 assert slice_tag['value'] == value
1581 print "Updated slice attribute", slice_tag_id
1583 def DeleteSliceTags(self):
1585 Delete any random slice attributes we may have added.
1588 for slice_tag_id in self.slice_tag_ids:
1589 self.api.DeleteSliceTag(slice_tag_id)
1592 assert not self.api.GetSliceTags([slice_tag_id])
1595 print "Deleted slice attribute", slice_tag_id
1598 assert not self.api.GetSliceTags(self.slice_tag_ids)
1600 self.slice_tag_ids = []
1603 parser = OptionParser()
1604 parser.add_option("-c", "--check", action = "store_true", default = False,
1605 help = "Check most actions (default: %default)")
1606 parser.add_option("-q", "--quiet", action = "store_true", default = False,
1607 help = "Be quiet (default: %default)")
1608 parser.add_option("-p","--preserve", action="store_true", default =False,
1609 help = "Do not delete created objects")
1610 parser.add_option("-t", "--tiny", action = "store_true", default = False,
1611 help = "Run a tiny test (default: %default)")
1612 parser.add_option("-s", "--short-names", action="store_true", dest="short_names", default = False,
1613 help = "Generate smaller names for checking UI rendering")
1614 (options, args) = parser.parse_args()
1616 test = Test(api = Shell(),
1617 check = options.check,
1618 verbose = not options.quiet,
1619 preserve = options.preserve)
1622 sizes = Test.sizes_tiny
1624 sizes = Test.sizes_default
1627 if options.short_names:
1628 namelengths = Test.namelengths_short
1630 namelengths = Test.namelengths_default
1634 if __name__ == "__main__":