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(100, 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,
272 namelengths_short = {
277 'sitename_contents':letters+digits+whitespace+punctuation,
278 'abbreviated_name':24,
279 'abbreviated_name_contents':letters+digits+whitespace+punctuation,
283 def __init__(self, api, check = True, verbose = True, preserve = False):
286 self.verbose = verbose
287 self.preserve = preserve
290 self.address_type_ids = []
291 self.address_ids = []
294 self.slice_type_ids = []
295 self.nodegroup_type_ids = []
296 self.ilink_type_ids = []
297 self.nodegroup_ids = []
299 self.interface_ids = []
302 self.conf_file_ids = []
304 self.slice_tag_ids = []
306 def Cardinals (self):
307 return [len(x) for x in (
308 self.api.GetNodes({},['node_id']),
309 self.api.GetSites({},['site_id']),
310 self.api.GetPersons({},['person_id']),
311 self.api.GetSlices({},['slice_id']),
314 def Run(self, **kwds):
316 Run a complete database and API consistency test. Populates
317 the database with a set of random entities, updates them, then
318 deletes them. Examples:
320 test.Run() # Defaults
321 test.Run(**Test.sizes_default) # Defaults
322 test.Run(**Test.sizes_tiny) # Tiny set
323 test.Run(sites = 123, slices_per_site = 4) # Defaults with overrides
326 cardinals_before=self.Cardinals()
327 print 'Cardinals before test (n,s,p,sl)',cardinals_before
332 print 'Preserving - delete skipped'
336 cardinals_after=self.Cardinals()
337 print 'Cardinals after test (n,s,p,sl)',cardinals_after
339 if cardinals_before != cardinals_after:
340 raise Exception, 'cardinals before and after differ - check deletion mechanisms'
342 def Add(self, **kwds):
344 Populate the database with a set of random entities. Examples:
349 sizes = self.sizes_default.copy()
352 self.AddSites(sizes['sites'])
353 self.AddAddressTypes(sizes['address_types'])
354 self.AddAddresses(sizes['addresses_per_site'])
355 self.AddPersons(sizes['persons_per_site'])
356 self.AddKeys(sizes['keys_per_person'])
357 self.AddTagTypes(sizes['slice_tags'],sizes['nodegroups'],sizes['ilinks'])
358 self.AddNodeGroups(sizes['nodegroups'])
359 self.AddNodes(sizes['nodes_per_site'])
360 self.AddInterfaces(sizes['interfaces_per_node'])
361 self.AddIlinks (sizes['ilinks'])
362 self.AddPCUs(sizes['pcus_per_site'])
363 self.AddConfFiles(sizes['conf_files'])
364 self.AddSlices(sizes['slices_per_site'])
365 self.AddSliceTags(sizes['attributes_per_slice'])
369 self.UpdateAddressTypes()
370 self.UpdateAddresses()
373 self.UpdateTagTypes()
374 self.UpdateNodeGroups()
376 self.UpdateInterfaces()
379 self.UpdateConfFiles()
381 self.UpdateSliceTags()
384 self.DeleteSliceTags()
387 self.DeleteConfFiles()
390 self.DeleteInterfaces()
393 self.DeleteNodeGroups()
394 self.DeleteTagTypes()
395 self.DeleteAddresses()
396 self.DeleteAddressTypes()
399 def AddSites(self, n = 10):
401 Add a number of random sites.
406 site_fields = random_site()
407 site_id = self.api.AddSite(site_fields)
409 # Should return a unique site_id
410 assert site_id not in self.site_ids
411 self.site_ids.append(site_id)
413 # Enable slice creation
414 site_fields['max_slices'] = randint(1, 10)
415 self.api.UpdateSite(site_id, site_fields)
419 site = self.api.GetSites([site_id])[0]
420 for field in site_fields:
421 assert site[field] == site_fields[field]
424 print "Added site", site_id
426 def UpdateSites(self):
428 Make random changes to any sites we may have added.
431 for site_id in self.site_ids:
433 site_fields = random_site()
434 # Do not change login_base
435 if 'login_base' in site_fields:
436 del site_fields['login_base']
437 self.api.UpdateSite(site_id, site_fields)
441 site = self.api.GetSites([site_id])[0]
442 for field in site_fields:
443 assert site[field] == site_fields[field]
446 print "Updated site", site_id
448 def DeleteSites(self):
450 Delete any random sites we may have added.
453 for site_id in self.site_ids:
454 self.api.DeleteSite(site_id)
457 assert not self.api.GetSites([site_id])
460 print "Deleted site", site_id
463 assert not self.api.GetSites(self.site_ids)
467 def AddAddressTypes(self, n = 2):
469 Add a number of random address types.
473 address_type_fields = random_address_type()
474 address_type_id = self.api.AddAddressType(address_type_fields)
476 # Should return a unique address_type_id
477 assert address_type_id not in self.address_type_ids
478 self.address_type_ids.append(address_type_id)
482 address_type = self.api.GetAddressTypes([address_type_id])[0]
483 for field in address_type_fields:
484 assert address_type[field] == address_type_fields[field]
487 print "Added address type", address_type_id
489 def UpdateAddressTypes(self):
491 Make random changes to any address types we may have added.
494 for address_type_id in self.address_type_ids:
495 # Update address_type
496 address_type_fields = random_address_type()
497 self.api.UpdateAddressType(address_type_id, address_type_fields)
501 address_type = self.api.GetAddressTypes([address_type_id])[0]
502 for field in address_type_fields:
503 assert address_type[field] == address_type_fields[field]
506 print "Updated address_type", address_type_id
508 def DeleteAddressTypes(self):
510 Delete any random address types we may have added.
513 for address_type_id in self.address_type_ids:
514 self.api.DeleteAddressType(address_type_id)
517 assert not self.api.GetAddressTypes([address_type_id])
520 print "Deleted address type", address_type_id
523 assert not self.api.GetAddressTypes(self.address_type_ids)
525 self.address_type_ids = []
527 def AddAddresses(self, per_site = 2):
529 Add a number of random addresses to each site.
532 for site_id in self.site_ids:
533 for i in range(per_site):
534 address_fields = random_address()
535 address_id = self.api.AddSiteAddress(site_id, address_fields)
537 # Should return a unique address_id
538 assert address_id not in self.address_ids
539 self.address_ids.append(address_id)
541 # Add random address type
542 if self.address_type_ids:
543 for address_type_id in random.sample(self.address_type_ids, 1):
544 self.api.AddAddressTypeToAddress(address_type_id, address_id)
548 address = self.api.GetAddresses([address_id])[0]
549 for field in address_fields:
550 assert address[field] == address_fields[field]
553 print "Added address", address_id, "to site", site_id
555 def UpdateAddresses(self):
557 Make random changes to any addresses we may have added.
560 for address_id in self.address_ids:
562 address_fields = random_address()
563 self.api.UpdateAddress(address_id, address_fields)
567 address = self.api.GetAddresses([address_id])[0]
568 for field in address_fields:
569 assert address[field] == address_fields[field]
572 print "Updated address", address_id
574 def DeleteAddresses(self):
576 Delete any random addresses we may have added.
579 for address_id in self.address_ids:
580 # Remove address types
581 address = self.api.GetAddresses([address_id])[0]
582 for address_type_id in address['address_type_ids']:
583 self.api.DeleteAddressTypeFromAddress(address_type_id, address_id)
586 address = self.api.GetAddresses([address_id])[0]
587 assert not address['address_type_ids']
589 self.api.DeleteAddress(address_id)
592 assert not self.api.GetAddresses([address_id])
595 print "Deleted address", address_id
598 assert not self.api.GetAddresses(self.address_ids)
600 self.address_ids = []
602 def AddPersons(self, per_site = 10):
604 Add a number of random users to each site.
607 for site_id in self.site_ids:
608 for i in range(per_site):
610 person_fields = random_person()
611 person_id = self.api.AddPerson(person_fields)
613 # Should return a unique person_id
614 assert person_id not in self.person_ids
615 self.person_ids.append(person_id)
619 person = self.api.GetPersons([person_id])[0]
620 for field in person_fields:
621 if field != 'password':
622 assert person[field] == person_fields[field]
624 auth = {'AuthMethod': "password",
625 'Username': person_fields['email'],
626 'AuthString': person_fields['password']}
629 # Check that user is disabled
631 assert not self.api.AuthCheck(auth)
635 # Add random set of roles
636 role_ids = random.sample([20, 30, 40], randint(1, 3))
637 for role_id in role_ids:
638 self.api.AddRoleToPerson(role_id, person_id)
641 person = self.api.GetPersons([person_id])[0]
642 assert set(role_ids) == set(person['role_ids'])
645 self.api.UpdatePerson(person_id, {'enabled': True})
648 # Check that user is enabled
649 assert self.api.AuthCheck(auth)
651 # Associate user with site
652 self.api.AddPersonToSite(person_id, site_id)
653 self.api.SetPersonPrimarySite(person_id, site_id)
656 person = self.api.GetPersons([person_id])[0]
657 assert person['site_ids'][0] == site_id
660 print "Added user", person_id, "to site", site_id
662 def UpdatePersons(self):
664 Make random changes to any users we may have added.
667 for person_id in self.person_ids:
669 person_fields = random_person()
671 person_fields['enabled'] = True
672 self.api.UpdatePerson(person_id, person_fields)
676 person = self.api.GetPersons([person_id])[0]
677 for field in person_fields:
678 if field != 'password':
679 assert person[field] == person_fields[field]
682 print "Updated person", person_id
684 person = self.api.GetPersons([person_id])[0]
686 # Associate user with a random set of sites
687 site_ids = random.sample(self.site_ids, randint(0, len(self.site_ids)))
688 for site_id in (set(site_ids) - set(person['site_ids'])):
689 self.api.AddPersonToSite(person_id, site_id)
690 for site_id in (set(person['site_ids']) - set(site_ids)):
691 self.api.DeletePersonFromSite(person_id, site_id)
694 self.api.SetPersonPrimarySite(person_id, site_ids[0])
697 person = self.api.GetPersons([person_id])[0]
698 assert set(site_ids) == set(person['site_ids'])
701 print "Updated person", person_id, "to sites", site_ids
703 def DeletePersons(self):
705 Delete any random users we may have added.
708 for person_id in self.person_ids:
710 person = self.api.GetPersons([person_id])[0]
711 for site_id in person['site_ids']:
712 self.api.DeletePersonFromSite(person_id, site_id)
715 person = self.api.GetPersons([person_id])[0]
716 assert not person['site_ids']
719 for role_id in person['role_ids']:
720 self.api.DeleteRoleFromPerson(role_id, person_id)
723 person = self.api.GetPersons([person_id])[0]
724 assert not person['role_ids']
727 self.api.UpdatePerson(person_id, {'enabled': False})
730 person = self.api.GetPersons([person_id])[0]
731 assert not person['enabled']
734 self.api.DeletePerson(person_id)
737 assert not self.api.GetPersons([person_id])
740 print "Deleted user", person_id
743 assert not self.api.GetPersons(self.person_ids)
747 def AddKeys(self, per_person = 2):
749 Add a number of random keys to each user.
752 key_types = self.api.GetKeyTypes()
754 raise Exception, "No key types"
756 for person_id in self.person_ids:
757 for i in range(per_person):
759 key_fields = random_key(key_types)
760 key_id = self.api.AddPersonKey(person_id, key_fields)
762 # Should return a unique key_id
763 assert key_id not in self.key_ids
764 self.key_ids.append(key_id)
768 key = self.api.GetKeys([key_id])[0]
769 for field in key_fields:
770 assert key[field] == key_fields[field]
772 # Add and immediately blacklist a key
773 key_fields = random_key(key_types)
774 key_id = self.api.AddPersonKey(person_id, key_fields)
776 self.api.BlacklistKey(key_id)
778 # Is effectively deleted
779 assert not self.api.GetKeys([key_id])
781 # Cannot be added again
783 key_id = self.api.AddPersonKey(person_id, key_fields)
789 print "Added key", key_id, "to user", person_id
791 def UpdateKeys(self):
793 Make random changes to any keys we may have added.
796 key_types = self.api.GetKeyTypes()
798 raise Exception, "No key types"
800 for key_id in self.key_ids:
802 key_fields = random_key(key_types)
803 self.api.UpdateKey(key_id, key_fields)
807 key = self.api.GetKeys([key_id])[0]
808 for field in key_fields:
809 assert key[field] == key_fields[field]
812 print "Updated key", key_id
814 def DeleteKeys(self):
816 Delete any random keys we may have added.
819 for key_id in self.key_ids:
820 self.api.DeleteKey(key_id)
823 assert not self.api.GetKeys([key_id])
826 print "Deleted key", key_id
829 assert not self.api.GetKeys(self.key_ids)
833 def AddNodeGroups(self, n = 10):
835 Add a number of random node groups.
840 tag_type_id = self.nodegroup_type_ids[i]
841 tagname=self.api.GetTagTypes([tag_type_id])[0]['tagname']
844 groupname = random_nodegroup() ['groupname']
846 nodegroup_id = self.api.AddNodeGroup(groupname, tagname, value)
848 # Should return a unique nodegroup_id
849 assert nodegroup_id not in self.nodegroup_ids
850 self.nodegroup_ids.append(nodegroup_id)
854 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
855 assert nodegroup['groupname'] == groupname
856 assert nodegroup['tagname'] == tagname
857 assert nodegroup['value'] == value
860 print "Added node group", nodegroup_id
862 def UpdateNodeGroups(self):
864 Make random changes to any node groups we may have added.
867 for nodegroup_id in self.nodegroup_ids:
869 groupname = random_nodegroup()['groupname']
870 # cannot change tagname
871 nodegroup_fields = { 'groupname':groupname }
872 self.api.UpdateNodeGroup(nodegroup_id, nodegroup_fields)
876 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
877 for field in nodegroup_fields:
878 assert nodegroup[field] == nodegroup_fields[field]
881 print "Updated node group", nodegroup_id
883 def DeleteNodeGroups(self):
885 Delete any random node groups we may have added.
888 for nodegroup_id in self.nodegroup_ids:
889 self.api.DeleteNodeGroup(nodegroup_id)
892 assert not self.api.GetNodeGroups([nodegroup_id])
895 print "Deleted node group", nodegroup_id
898 assert not self.api.GetNodeGroups(self.nodegroup_ids)
900 self.nodegroup_ids = []
902 def AddNodes(self, per_site = 2):
904 Add a number of random nodes to each site. Each node will also
905 be added to a random node group if AddNodeGroups() was
909 node_types = self.api.GetNodeTypes()
911 raise Exception, "No node types"
912 boot_states = self.api.GetBootStates()
914 raise Exception, "No boot states"
916 for site_id in self.site_ids:
917 for i in range(per_site):
919 node_fields = random_node(node_types,boot_states)
920 node_id = self.api.AddNode(site_id, node_fields)
922 # Should return a unique node_id
923 assert node_id not in self.node_ids
924 self.node_ids.append(node_id)
926 # Add to a random set of node groups
927 nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
928 for nodegroup_id in nodegroup_ids:
929 tagname = self.api.GetNodeGroups([nodegroup_id])[0]['tagname']
930 self.api.AddNodeTag( node_id, tagname, 'yes' )
934 node = self.api.GetNodes([node_id])[0]
935 for field in node_fields:
936 if field not in tag_fields:
937 assert node[field] == node_fields[field]
940 print "Added node", node_id
942 def UpdateNodes(self):
944 Make random changes to any nodes we may have added.
947 node_types = self.api.GetNodeTypes()
949 raise Exception, "No node types"
950 boot_states = self.api.GetBootStates()
952 raise Exception, "No boot states"
954 for node_id in self.node_ids:
956 node_fields = random_node(node_types,boot_states)
957 self.api.UpdateNode(node_id, node_fields)
959 node = self.api.GetNodes([node_id])[0]
961 # Add to a random set of node groups
962 nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
963 for nodegroup_id in (set(nodegroup_ids) - set(node['nodegroup_ids'])):
964 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
965 tagname = nodegroup['tagname']
966 node_tags = self.api.GetNodeTags({'node_id':node_id,'tagname':tagname})
968 self.api.AddNodeTag(node_id,tagname,'yes')
970 node_tag=node_tags[0]
971 self.api.UpdateNodeTag(node_tag['node_tag_id'],'yes')
972 for nodegroup_id in (set(node['nodegroup_ids']) - set(nodegroup_ids)):
973 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
974 tagname = nodegroup['tagname']
975 node_tags = self.api.GetNodeTags({'node_id':node_id,'tagname':tagname})
977 self.api.AddNodeTag(node_id,tagname,'no')
979 node_tag=node_tags[0]
980 self.api.UpdateNodeTag(node_tag['node_tag_id'],'no')
984 node = self.api.GetNodes([node_id])[0]
985 for field in node_fields:
986 if field not in tag_fields:
987 if node[field] != node_fields[field]:
988 raise Exception, "Unexpected field %s in node after GetNodes()"%field
989 assert set(nodegroup_ids) == set(node['nodegroup_ids'])
991 print 'WARNING: skipping updatenode with tags as this is not implemented yet'
992 # again when fetching 'arch' explicitly
993 node2 = self.api.GetNodes([node_id],node_fields.keys())[0]
994 for field in node_fields:
995 if node2[field] != node_fields[field]:
996 raise Exception, "Unexpected field %s in node after GetNodes(tags)"%field
999 print "Updated node", node_id
1001 def DeleteNodes(self):
1003 Delete any random nodes we may have added.
1006 for node_id in self.node_ids:
1007 # Remove from node groups
1008 node = self.api.GetNodes([node_id])[0]
1009 for node_tag in GetNodeTags ( {'node_id': node_id} ):
1010 self.api.UpdateNodeTag(node_tag['node_tag_id'],'')
1013 node = self.api.GetNodes([node_id])[0]
1014 assert not node['nodegroup_ids']
1016 self.api.DeleteNode(node_id)
1019 assert not self.api.GetNodes([node_id])
1022 print "Deleted node", node_id
1025 assert not self.api.GetNodes(self.node_ids)
1029 def AddInterfaces(self, per_node = 1):
1031 Add a number of random network interfaces to each node.
1034 network_methods = self.api.GetNetworkMethods()
1035 if not network_methods:
1036 raise Exception, "No network methods"
1038 network_types = self.api.GetNetworkTypes()
1039 if not network_types:
1040 raise Exception, "No network types"
1042 for node_id in self.node_ids:
1043 for i in range(per_node):
1044 method = random.sample(network_methods, 1)[0]
1045 type = random.sample(network_types, 1)[0]
1048 interface_fields = random_interface(method, type)
1049 interface_id = self.api.AddInterface(node_id, interface_fields)
1051 # Should return a unique interface_id
1052 assert interface_id not in self.interface_ids
1053 self.interface_ids.append(interface_id)
1057 interface = self.api.GetInterfaces([interface_id])[0]
1058 for field in interface_fields:
1059 assert interface[field] == interface_fields[field]
1062 print "Added interface", interface_id, "to node", node_id
1064 def UpdateInterfaces(self):
1066 Make random changes to any network interfaces we may have added.
1069 network_methods = self.api.GetNetworkMethods()
1070 if not network_methods:
1071 raise Exception, "No network methods"
1073 network_types = self.api.GetNetworkTypes()
1074 if not network_types:
1075 raise Exception, "No network types"
1077 for interface_id in self.interface_ids:
1078 method = random.sample(network_methods, 1)[0]
1079 type = random.sample(network_types, 1)[0]
1082 interface_fields = random_interface(method, type)
1083 self.api.UpdateInterface(interface_id, interface_fields)
1087 interface = self.api.GetInterfaces([interface_id])[0]
1088 for field in interface_fields:
1089 assert interface[field] == interface_fields[field]
1092 print "Updated interface", interface_id
1094 def DeleteInterfaces(self):
1096 Delete any random network interfaces we may have added.
1099 for interface_id in self.interface_ids:
1100 self.api.DeleteInterface(interface_id)
1103 assert not self.api.GetInterfaces([interface_id])
1106 print "Deleted interface", interface_id
1109 assert not self.api.GetInterfaces(self.interface_ids)
1111 self.interface_ids = []
1113 def AddIlinks (self, n):
1115 Add random links between interfaces.
1119 src = random.sample(self.interface_ids,1)[0]
1120 dst = random.sample(self.interface_ids,1)[0]
1121 ilink_id = self.api.AddIlink (src,dst,
1122 self.ilink_type_ids[i],
1125 assert ilink_id not in self.ilink_ids
1126 self.ilink_ids.append(ilink_id)
1129 print 'Added Ilink',ilink_id,' - attached interface',src,'to',dst
1132 retrieve=GetIlinks({'src_interface_id':src,'dst_interface_id':dst,
1133 'tag_type_id':self.ilink_type_ids[i]})
1134 assert ilink_id==retrieve[0]['ilink_id']
1137 def UpdateIlinks (self):
1139 for ilink_id in self.ilink_ids:
1140 new_value=random_ilink()
1141 self.api.UpdateIlink(ilink_id,new_value)
1144 ilink=self.api.GetIlinks([ilink_id])[0]
1145 assert ilink['value'] == new_value
1148 print 'Updated Ilink',ilink_id
1150 def DeleteIlinks (self):
1151 for ilink_id in self.ilink_ids:
1152 self.api.DeleteIlink(ilink_id)
1155 assert not self.api.GetIlinks({'ilink_id':ilink_id})
1158 print 'Deleted Ilink',ilink_id
1161 assert not self.api.GetIlinks(self.ilink_ids)
1166 def AddPCUs(self, per_site = 1):
1168 Add a number of random PCUs to each site. Each node at the
1169 site will be added to a port on the PCU if AddNodes() was
1173 for site_id in self.site_ids:
1174 for i in range(per_site):
1176 pcu_fields = random_pcu()
1177 pcu_id = self.api.AddPCU(site_id, pcu_fields)
1179 # Should return a unique pcu_id
1180 assert pcu_id not in self.pcu_ids
1181 self.pcu_ids.append(pcu_id)
1183 # Add each node at this site to a different port on this PCU
1184 site = self.api.GetSites([site_id])[0]
1185 port = randint(1, 10)
1186 for node_id in site['node_ids']:
1187 self.api.AddNodeToPCU(node_id, pcu_id, port)
1192 pcu = self.api.GetPCUs([pcu_id])[0]
1193 for field in pcu_fields:
1194 assert pcu[field] == pcu_fields[field]
1197 print "Added PCU", pcu_id, "to site", site_id
1199 def UpdatePCUs(self):
1201 Make random changes to any PCUs we may have added.
1204 for pcu_id in self.pcu_ids:
1206 pcu_fields = random_pcu()
1207 self.api.UpdatePCU(pcu_id, pcu_fields)
1211 pcu = self.api.GetPCUs([pcu_id])[0]
1212 for field in pcu_fields:
1213 assert pcu[field] == pcu_fields[field]
1216 print "Updated PCU", pcu_id
1218 def DeletePCUs(self):
1220 Delete any random nodes we may have added.
1223 for pcu_id in self.pcu_ids:
1224 # Remove nodes from PCU
1225 pcu = self.api.GetPCUs([pcu_id])[0]
1226 for node_id in pcu['node_ids']:
1227 self.api.DeleteNodeFromPCU(node_id, pcu_id)
1230 pcu = self.api.GetPCUs([pcu_id])[0]
1231 assert not pcu['node_ids']
1233 self.api.DeletePCU(pcu_id)
1236 assert not self.api.GetPCUs([pcu_id])
1239 print "Deleted PCU", pcu_id
1242 assert not self.api.GetPCUs(self.pcu_ids)
1246 def AddConfFiles(self, n = 10):
1248 Add a number of random global configuration files.
1254 # Add a random configuration file
1255 conf_files.append(random_conf_file())
1258 # Add a nodegroup override file
1259 nodegroup_conf_file = conf_files[0].copy()
1260 nodegroup_conf_file['source'] = randpath(255)
1261 conf_files.append(nodegroup_conf_file)
1263 # Add a node override file
1264 node_conf_file = conf_files[0].copy()
1265 node_conf_file['source'] = randpath(255)
1266 conf_files.append(node_conf_file)
1268 for conf_file_fields in conf_files:
1269 conf_file_id = self.api.AddConfFile(conf_file_fields)
1271 # Should return a unique conf_file_id
1272 assert conf_file_id not in self.conf_file_ids
1273 self.conf_file_ids.append(conf_file_id)
1276 if conf_file_fields == nodegroup_conf_file and self.nodegroup_ids:
1277 nodegroup_id = random.sample(self.nodegroup_ids, 1)[0]
1278 self.api.AddConfFileToNodeGroup(conf_file_id, nodegroup_id)
1283 if conf_file_fields == node_conf_file and self.node_ids:
1284 node_id = random.sample(self.node_ids, 1)[0]
1285 self.api.AddConfFileToNode(conf_file_id, node_id)
1290 # Check configuration file
1291 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1292 for field in conf_file_fields:
1293 assert conf_file[field] == conf_file_fields[field]
1296 print "Added configuration file", conf_file_id,
1297 if nodegroup_id is not None:
1298 print "to node group", nodegroup_id,
1299 elif node_id is not None:
1300 print "to node", node_id,
1303 def UpdateConfFiles(self):
1305 Make random changes to any configuration files we may have added.
1308 for conf_file_id in self.conf_file_ids:
1309 # Update configuration file
1310 conf_file_fields = random_conf_file()
1311 # Do not update dest so that it remains an override if set
1312 if 'dest' in conf_file_fields:
1313 del conf_file_fields['dest']
1314 self.api.UpdateConfFile(conf_file_id, conf_file_fields)
1317 # Check configuration file
1318 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1319 for field in conf_file_fields:
1320 assert conf_file[field] == conf_file_fields[field]
1323 print "Updated configuration file", conf_file_id
1325 def DeleteConfFiles(self):
1327 Delete any random configuration files we may have added.
1330 for conf_file_id in self.conf_file_ids:
1331 self.api.DeleteConfFile(conf_file_id)
1334 assert not self.api.GetConfFiles([conf_file_id])
1337 print "Deleted configuration file", conf_file_id
1340 assert not self.api.GetConfFiles(self.conf_file_ids)
1342 self.conf_file_ids = []
1344 def AddTagTypes(self,n_sa,n_ng,n_il):
1346 Add as many tag types as there are nodegroups,
1347 will use value=yes for each nodegroup
1350 roles = self.api.GetRoles()
1352 raise Exception, "No roles"
1353 role_ids = [role['role_id'] for role in roles]
1355 for i in range (n_sa + n_ng + n_il):
1356 tag_type_fields = random_tag_type (role_ids)
1357 tag_type_id = self.api.AddTagType (tag_type_fields)
1359 assert tag_type_id not in \
1360 self.slice_type_ids + \
1361 self.nodegroup_type_ids + \
1365 self.slice_type_ids.append(tag_type_id)
1366 elif i < n_sa+n_ng :
1367 self.nodegroup_type_ids.append(tag_type_id)
1369 self.ilink_type_ids.append(tag_type_id)
1372 tag_type = self.api.GetTagTypes([tag_type_id])[0]
1373 for field in tag_type_fields:
1374 assert tag_type[field] == tag_type_fields[field]
1376 print "Updated slice attribute type", tag_type_id
1378 def UpdateTagTypes(self):
1380 Make random changes to any slice attribute types we may have added.
1383 roles = self.api.GetRoles()
1385 raise Exception, "No roles"
1386 role_ids = [role['role_id'] for role in roles]
1388 for tag_type_id in self.slice_type_ids + self.nodegroup_type_ids + self.ilink_type_ids:
1389 # Update slice attribute type
1390 tag_type_fields = random_tag_type(role_ids)
1391 self.api.UpdateTagType(tag_type_id, tag_type_fields)
1394 # Check slice attribute type
1395 tag_type = self.api.GetTagTypes([tag_type_id])[0]
1396 for field in tag_type_fields:
1397 assert tag_type[field] == tag_type_fields[field]
1399 print "Updated slice attribute type", tag_type_id
1401 def DeleteTagTypes(self):
1403 Delete any random slice attribute types we may have added.
1406 for tag_type_id in self.slice_type_ids + self.nodegroup_type_ids + self.ilink_type_ids:
1407 self.api.DeleteTagType(tag_type_id)
1410 assert not self.api.GetTagTypes([tag_type_id])
1413 print "Deleted slice attribute type", tag_type_id
1416 assert not self.api.GetTagTypes(self.slice_type_ids+self.nodegroup_type_ids+self.ilink_type_ids)
1418 self.slice_type_ids = []
1419 self.nodegroup_type_ids = []
1421 def AddSlices(self, per_site = 10):
1423 Add a number of random slices per site.
1426 for site in self.api.GetSites(self.site_ids):
1427 for i in range(min(per_site, site['max_slices'])):
1429 slice_fields = random_slice(site['login_base'])
1430 slice_id = self.api.AddSlice(slice_fields)
1432 # Should return a unique slice_id
1433 assert slice_id not in self.slice_ids
1434 self.slice_ids.append(slice_id)
1436 # Add slice to a random set of nodes
1437 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1439 self.api.AddSliceToNodes(slice_id, node_ids)
1441 # Add random set of site users to slice
1442 person_ids = random.sample(site['person_ids'], randint(0, len(site['person_ids'])))
1443 for person_id in person_ids:
1444 self.api.AddPersonToSlice(person_id, slice_id)
1448 slice = self.api.GetSlices([slice_id])[0]
1449 for field in slice_fields:
1450 assert slice[field] == slice_fields[field]
1452 assert set(node_ids) == set(slice['node_ids'])
1453 assert set(person_ids) == set(slice['person_ids'])
1456 print "Added slice", slice_id, "to site", site['site_id'],
1458 print "and nodes", node_ids,
1461 print "Added users", site['person_ids'], "to slice", slice_id
1463 def UpdateSlices(self):
1465 Make random changes to any slices we may have added.
1468 for slice_id in self.slice_ids:
1470 slice_fields = random_slice("unused")
1471 # Cannot change slice name
1472 if 'name' in slice_fields:
1473 del slice_fields['name']
1474 self.api.UpdateSlice(slice_id, slice_fields)
1476 slice = self.api.GetSlices([slice_id])[0]
1478 # Add slice to a random set of nodes
1479 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1480 self.api.AddSliceToNodes(slice_id, list(set(node_ids) - set(slice['node_ids'])))
1481 self.api.DeleteSliceFromNodes(slice_id, list(set(slice['node_ids']) - set(node_ids)))
1483 # Add random set of users to slice
1484 person_ids = random.sample(self.person_ids, randint(0, len(self.person_ids)))
1485 for person_id in (set(person_ids) - set(slice['person_ids'])):
1486 self.api.AddPersonToSlice(person_id, slice_id)
1487 for person_id in (set(slice['person_ids']) - set(person_ids)):
1488 self.api.DeletePersonFromSlice(person_id, slice_id)
1491 slice = self.api.GetSlices([slice_id])[0]
1492 for field in slice_fields:
1493 assert slice[field] == slice_fields[field]
1494 assert set(node_ids) == set(slice['node_ids'])
1495 assert set(person_ids) == set(slice['person_ids'])
1498 print "Updated slice", slice_id
1499 print "Added nodes", node_ids, "to slice", slice_id
1500 print "Added persons", person_ids, "to slice", slice_id
1502 def DeleteSlices(self):
1504 Delete any random slices we may have added.
1507 for slice_id in self.slice_ids:
1508 self.api.DeleteSlice(slice_id)
1511 assert not self.api.GetSlices([slice_id])
1514 print "Deleted slice", slice_id
1517 assert not self.api.GetSlices(self.slice_ids)
1521 def AddSliceTags(self, per_slice = 2):
1523 Add a number of random slices per site.
1526 if not self.slice_type_ids:
1529 for slice_id in self.slice_ids:
1530 slice = self.api.GetSlices([slice_id])[0]
1532 for i in range(per_slice):
1533 # Set a random slice/sliver attribute
1534 for tag_type_id in random.sample(self.slice_type_ids, 1):
1535 value = randstr(16, letters + '_' + digits)
1536 # Make it a sliver attribute with 50% probability
1537 if slice['node_ids']:
1538 node_id = random.sample(slice['node_ids'] + [None] * len(slice['node_ids']), 1)[0]
1542 # Add slice attribute
1544 slice_tag_id = self.api.AddSliceTag(slice_id, tag_type_id, value)
1546 slice_tag_id = self.api.AddSliceTag(slice_id, tag_type_id, value, node_id)
1548 # Should return a unique slice_tag_id
1549 assert slice_tag_id not in self.slice_tag_ids
1550 self.slice_tag_ids.append(slice_tag_id)
1553 # Check slice attribute
1554 slice_tag = self.api.GetSliceTags([slice_tag_id])[0]
1555 for field in 'tag_type_id', 'slice_id', 'node_id', 'slice_tag_id', 'value':
1556 assert slice_tag[field] == locals()[field]
1559 print "Added slice attribute", slice_tag_id, "of type", tag_type_id,
1560 if node_id is not None:
1561 print "to node", node_id,
1564 def UpdateSliceTags(self):
1566 Make random changes to any slice attributes we may have added.
1569 for slice_tag_id in self.slice_tag_ids:
1570 # Update slice attribute
1571 value = randstr(16, letters + '_' + digits)
1572 self.api.UpdateSliceTag(slice_tag_id, value)
1574 # Check slice attribute again
1575 slice_tag = self.api.GetSliceTags([slice_tag_id])[0]
1576 assert slice_tag['value'] == value
1579 print "Updated slice attribute", slice_tag_id
1581 def DeleteSliceTags(self):
1583 Delete any random slice attributes we may have added.
1586 for slice_tag_id in self.slice_tag_ids:
1587 self.api.DeleteSliceTag(slice_tag_id)
1590 assert not self.api.GetSliceTags([slice_tag_id])
1593 print "Deleted slice attribute", slice_tag_id
1596 assert not self.api.GetSliceTags(self.slice_tag_ids)
1598 self.slice_tag_ids = []
1601 parser = OptionParser()
1602 parser.add_option("-c", "--check", action = "store_true", default = False,
1603 help = "Check most actions (default: %default)")
1604 parser.add_option("-q", "--quiet", action = "store_true", default = False,
1605 help = "Be quiet (default: %default)")
1606 parser.add_option("-p","--preserve", action="store_true", default =False,
1607 help = "Do not delete created objects")
1608 parser.add_option("-t", "--tiny", action = "store_true", default = False,
1609 help = "Run a tiny test (default: %default)")
1610 parser.add_option("-s", "--short-names", action="store_true", dest="short_names", default = False,
1611 help = "Generate smaller names for checking UI rendering")
1612 (options, args) = parser.parse_args()
1614 test = Test(api = Shell(),
1615 check = options.check,
1616 verbose = not options.quiet,
1617 preserve = options.preserve)
1620 sizes = Test.sizes_tiny
1622 sizes = Test.sizes_default
1625 if options.short_names:
1626 namelengths = Test.namelengths_short
1628 namelengths = Test.namelengths_default
1632 if __name__ == "__main__":