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
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)
69 # 1. Each part begins and ends with a letter or number.
70 # 2. Each part except the last can contain letters, numbers, or hyphens.
71 # 3. Each part is between 1 and 64 characters, including the trailing dot.
72 # 4. At least two parts.
73 # 5. Last part can only contain between 2 and 6 letters.
74 hostname = 'a' + randstr(61, letters + digits + '-') + '1.' + \
75 'b' + randstr(61, letters + digits + '-') + '2.' + \
76 'c' + randstr(5, letters)
81 for i in range(randint(1, 10)):
82 parts.append(randstr(randint(1, 30), ascii_xml_chars))
83 return u'/'.join(parts)[0:length]
86 return (randstr(100, letters + digits) + "@" + randhostname()).lower()
88 def randkey(bits = 2048):
89 ssh_key_types = ["ssh-dss", "ssh-rsa"]
90 key_type = random.sample(ssh_key_types, 1)[0]
91 return ' '.join([key_type,
92 base64.b64encode(''.join(randstr(bits / 8).encode("utf-8"))),
98 'abbreviated_name': randstr(50),
99 'login_base': randstr(20, letters).lower(),
100 'latitude': int(randfloat(-90.0, 90.0) * 1000) / 1000.0,
101 'longitude': int(randfloat(-180.0, 180.0) * 1000) / 1000.0,
104 def random_address_type():
107 'description': randstr(254),
110 def random_address():
112 'line1': randstr(254),
113 'line2': randstr(254),
114 'line3': randstr(254),
115 'city': randstr(254),
116 'state': randstr(254),
117 'postalcode': randstr(64),
118 'country': randstr(128),
123 'first_name': randstr(128),
124 'last_name': randstr(128),
125 'email': randemail(),
127 # Accounts are disabled by default
129 'password': randstr(254),
132 def random_key(key_types):
134 'key_type': random.sample(key_types, 1)[0],
138 def random_nodegroup():
141 'description': randstr(200),
144 def random_node(boot_states):
146 'hostname': randhostname(),
147 'boot_state': random.sample(boot_states, 1)[0],
148 'model': randstr(255),
149 'version': randstr(64),
152 def random_nodenetwork(method, type):
153 nodenetwork_fields = {
156 'bwlimit': randint(500000, 10000000),
160 ip = randint(0, 0xffffffff)
161 netmask = (0xffffffff << randint(2, 31)) & 0xffffffff
162 network = ip & netmask
163 broadcast = ((ip & netmask) | ~netmask) & 0xffffffff
164 gateway = randint(network + 1, broadcast - 1)
165 dns1 = randint(0, 0xffffffff)
167 for field in 'ip', 'netmask', 'network', 'broadcast', 'gateway', 'dns1':
168 nodenetwork_fields[field] = socket.inet_ntoa(struct.pack('>L', locals()[field]))
170 return nodenetwork_fields
174 'hostname': randhostname(),
175 'ip': socket.inet_ntoa(struct.pack('>L', randint(0, 0xffffffff))),
176 'protocol': randstr(16),
177 'username': randstr(254),
178 'password': randstr(254),
179 'notes': randstr(254),
180 'model': randstr(32),
183 def random_conf_file():
185 'enabled': bool(randint()),
186 'source': randpath(255),
187 'dest': randpath(255),
188 'file_permissions': "%#o" % randint(0, 512),
189 'file_owner': randstr(32, letters + '_' + digits),
190 'file_group': randstr(32, letters + '_' + digits),
191 'preinstall_cmd': randpath(100),
192 'postinstall_cmd': randpath(100),
193 'error_cmd': randpath(100),
194 'ignore_cmd_errors': bool(randint()),
195 'always_update': bool(randint()),
198 def random_attribute_type(role_ids):
200 'name': randstr(100),
201 'description': randstr(254),
202 'min_role_id': random.sample(role_ids, 1)[0],
205 def random_slice(login_base):
207 'name': login_base + "_" + randstr(11, letters).lower(),
208 'url': "http://" + randhostname() + "/",
209 'description': randstr(2048),
216 'addresses_per_site': 1,
217 'persons_per_site': 1,
218 'keys_per_person': 1,
221 'nodenetworks_per_node': 1,
224 'attribute_types': 1,
225 'slices_per_site': 1,
226 'attributes_per_slice': 1,
232 'addresses_per_site': 2,
233 'persons_per_site': 10,
234 'keys_per_person': 2,
237 'nodenetworks_per_node': 1,
240 'attribute_types': 10,
241 'slices_per_site': 10,
242 'attributes_per_slice': 2,
245 def __init__(self, api, check = True, verbose = True):
248 self.verbose = verbose
251 self.address_type_ids = []
252 self.address_ids = []
255 self.nodegroup_ids = []
257 self.nodenetwork_ids = []
259 self.conf_file_ids = []
260 self.attribute_type_ids = []
262 self.slice_attribute_ids = []
264 def Run(self, **kwds):
266 Run a complete database and API consistency test. Populates
267 the database with a set of random entities, updates them, then
268 deletes them. Examples:
270 test.Run() # Defaults
271 test.Run(**Test.default) # Defaults
272 test.Run(**Test.tiny) # Tiny set
273 test.Run(sites = 123, slices_per_site = 4) # Defaults with overrides
282 def Add(self, **kwds):
284 Populate the database with a set of random entities. Examples:
286 test.populate() # Defaults
287 test.populate(Test.tiny) # Tiny set
288 test.populate(sites = 123, slices_per_site = 4) # Defaults with overrides
291 params = self.default.copy()
294 self.AddSites(params['sites'])
295 self.AddAddressTypes(params['address_types'])
296 self.AddAddresses(params['addresses_per_site'])
297 self.AddPersons(params['persons_per_site'])
298 self.AddKeys(params['keys_per_person'])
299 self.AddNodeGroups(params['nodegroups'])
300 self.AddNodes(params['nodes_per_site'])
301 self.AddNodeNetworks(params['nodenetworks_per_node'])
302 self.AddPCUs(params['pcus_per_site'])
303 self.AddConfFiles(params['conf_files'])
304 self.AddSliceAttributeTypes(params['attribute_types'])
305 self.AddSlices(params['slices_per_site'])
306 self.AddSliceAttributes(params['attributes_per_slice'])
310 self.UpdateAddressTypes()
311 self.UpdateAddresses()
314 self.UpdateNodeGroups()
316 self.UpdateNodeNetworks()
318 self.UpdateConfFiles()
319 self.UpdateSliceAttributeTypes()
321 self.UpdateSliceAttributes()
324 self.DeleteSliceAttributes()
326 self.DeleteSliceAttributeTypes()
328 self.DeleteConfFiles()
330 self.DeleteNodeNetworks()
333 self.DeleteNodeGroups()
334 self.DeleteAddresses()
335 self.DeleteAddressTypes()
338 def AddSites(self, n = 10):
340 Add a number of random sites.
345 site_fields = random_site()
346 site_id = self.api.AddSite(site_fields)
348 # Should return a unique site_id
349 assert site_id not in self.site_ids
350 self.site_ids.append(site_id)
352 # Enable slice creation
353 site_fields['max_slices'] = randint(1, 10)
354 self.api.UpdateSite(site_id, site_fields)
358 site = self.api.GetSites([site_id])[0]
359 for field in site_fields:
360 assert site[field] == site_fields[field]
363 print "Added site", site_id
365 def UpdateSites(self):
367 Make random changes to any sites we may have added.
370 for site_id in self.site_ids:
372 site_fields = random_site()
373 # Do not change login_base
374 if 'login_base' in site_fields:
375 del site_fields['login_base']
376 self.api.UpdateSite(site_id, site_fields)
380 site = self.api.GetSites([site_id])[0]
381 for field in site_fields:
382 assert site[field] == site_fields[field]
385 print "Updated site", site_id
387 def DeleteSites(self):
389 Delete any random sites we may have added.
392 for site_id in self.site_ids:
393 self.api.DeleteSite(site_id)
396 assert not self.api.GetSites([site_id])
399 print "Deleted site", site_id
402 assert not self.api.GetSites(self.site_ids)
406 def AddAddressTypes(self, n = 2):
408 Add a number of random address types.
412 address_type_fields = random_address_type()
413 address_type_id = self.api.AddAddressType(address_type_fields)
415 # Should return a unique address_type_id
416 assert address_type_id not in self.address_type_ids
417 self.address_type_ids.append(address_type_id)
421 address_type = self.api.GetAddressTypes([address_type_id])[0]
422 for field in address_type_fields:
423 assert address_type[field] == address_type_fields[field]
426 print "Added address type", address_type_id
428 def UpdateAddressTypes(self):
430 Make random changes to any address types we may have added.
433 for address_type_id in self.address_type_ids:
434 # Update address_type
435 address_type_fields = random_address_type()
436 self.api.UpdateAddressType(address_type_id, address_type_fields)
440 address_type = self.api.GetAddressTypes([address_type_id])[0]
441 for field in address_type_fields:
442 assert address_type[field] == address_type_fields[field]
445 print "Updated address_type", address_type_id
447 def DeleteAddressTypes(self):
449 Delete any random address types we may have added.
452 for address_type_id in self.address_type_ids:
453 self.api.DeleteAddressType(address_type_id)
456 assert not self.api.GetAddressTypes([address_type_id])
459 print "Deleted address type", address_type_id
462 assert not self.api.GetAddressTypes(self.address_type_ids)
464 self.address_type_ids = []
466 def AddAddresses(self, per_site = 2):
468 Add a number of random addresses to each site.
471 for site_id in self.site_ids:
472 for i in range(per_site):
473 address_fields = random_address()
474 address_id = self.api.AddSiteAddress(site_id, address_fields)
476 # Should return a unique address_id
477 assert address_id not in self.address_ids
478 self.address_ids.append(address_id)
480 # Add random address type
481 if self.address_type_ids:
482 for address_type_id in random.sample(self.address_type_ids, 1):
483 self.api.AddAddressTypeToAddress(address_type_id, address_id)
487 address = self.api.GetAddresses([address_id])[0]
488 for field in address_fields:
489 assert address[field] == address_fields[field]
492 print "Added address", address_id, "to site", site_id
494 def UpdateAddresses(self):
496 Make random changes to any addresses we may have added.
499 for address_id in self.address_ids:
501 address_fields = random_address()
502 self.api.UpdateAddress(address_id, address_fields)
506 address = self.api.GetAddresses([address_id])[0]
507 for field in address_fields:
508 assert address[field] == address_fields[field]
511 print "Updated address", address_id
513 def DeleteAddresses(self):
515 Delete any random addresses we may have added.
518 for address_id in self.address_ids:
519 # Remove address types
520 address = self.api.GetAddresses([address_id])[0]
521 for address_type_id in address['address_type_ids']:
522 self.api.DeleteAddressTypeFromAddress(address_type_id, address_id)
525 address = self.api.GetAddresses([address_id])[0]
526 assert not address['address_type_ids']
528 self.api.DeleteAddress(address_id)
531 assert not self.api.GetAddresses([address_id])
534 print "Deleted address", address_id
537 assert not self.api.GetAddresses(self.address_ids)
539 self.address_ids = []
541 def AddPersons(self, per_site = 10):
543 Add a number of random users to each site.
546 for site_id in self.site_ids:
547 for i in range(per_site):
549 person_fields = random_person()
550 person_id = self.api.AddPerson(person_fields)
552 # Should return a unique person_id
553 assert person_id not in self.person_ids
554 self.person_ids.append(person_id)
558 person = self.api.GetPersons([person_id])[0]
559 for field in person_fields:
560 if field != 'password':
561 assert person[field] == person_fields[field]
563 auth = {'AuthMethod': "password",
564 'Username': person_fields['email'],
565 'AuthString': person_fields['password']}
568 # Check that user is disabled
570 assert not self.api.AuthCheck(auth)
574 # Add random set of roles
575 role_ids = random.sample([20, 30, 40], randint(1, 3))
576 for role_id in role_ids:
577 self.api.AddRoleToPerson(role_id, person_id)
580 person = self.api.GetPersons([person_id])[0]
581 assert set(role_ids) == set(person['role_ids'])
584 self.api.UpdatePerson(person_id, {'enabled': True})
587 # Check that user is enabled
588 assert self.api.AuthCheck(auth)
590 # Associate user with site
591 self.api.AddPersonToSite(person_id, site_id)
592 self.api.SetPersonPrimarySite(person_id, site_id)
595 person = self.api.GetPersons([person_id])[0]
596 assert person['site_ids'][0] == site_id
599 print "Added user", person_id, "to site", site_id
601 def UpdatePersons(self):
603 Make random changes to any users we may have added.
606 for person_id in self.person_ids:
608 person_fields = random_person()
610 person_fields['enabled'] = True
611 self.api.UpdatePerson(person_id, person_fields)
615 person = self.api.GetPersons([person_id])[0]
616 for field in person_fields:
617 if field != 'password':
618 assert person[field] == person_fields[field]
621 print "Updated person", person_id
623 person = self.api.GetPersons([person_id])[0]
625 # Associate user with a random set of sites
626 site_ids = random.sample(self.site_ids, randint(0, len(self.site_ids)))
627 for site_id in (set(site_ids) - set(person['site_ids'])):
628 self.api.AddPersonToSite(person_id, site_id)
629 for site_id in (set(person['site_ids']) - set(site_ids)):
630 self.api.DeletePersonFromSite(person_id, site_id)
633 self.api.SetPersonPrimarySite(person_id, site_ids[0])
636 person = self.api.GetPersons([person_id])[0]
637 assert set(site_ids) == set(person['site_ids'])
640 print "Updated person", person_id, "to sites", site_ids
642 def DeletePersons(self):
644 Delete any random users we may have added.
647 for person_id in self.person_ids:
649 person = self.api.GetPersons([person_id])[0]
650 for site_id in person['site_ids']:
651 self.api.DeletePersonFromSite(person_id, site_id)
654 person = self.api.GetPersons([person_id])[0]
655 assert not person['site_ids']
658 for role_id in person['role_ids']:
659 self.api.DeleteRoleFromPerson(role_id, person_id)
662 person = self.api.GetPersons([person_id])[0]
663 assert not person['role_ids']
666 self.api.UpdatePerson(person_id, {'enabled': False})
669 person = self.api.GetPersons([person_id])[0]
670 assert not person['enabled']
673 self.api.DeletePerson(person_id)
676 assert not self.api.GetPersons([person_id])
679 print "Deleted user", person_id
682 assert not self.api.GetPersons(self.person_ids)
686 def AddKeys(self, per_person = 2):
688 Add a number of random keys to each user.
691 key_types = self.api.GetKeyTypes()
693 raise Exception, "No key types"
695 for person_id in self.person_ids:
696 for i in range(per_person):
698 key_fields = random_key(key_types)
699 key_id = self.api.AddPersonKey(person_id, key_fields)
701 # Should return a unique key_id
702 assert key_id not in self.key_ids
703 self.key_ids.append(key_id)
707 key = self.api.GetKeys([key_id])[0]
708 for field in key_fields:
709 assert key[field] == key_fields[field]
711 # Add and immediately blacklist a key
712 key_fields = random_key(key_types)
713 key_id = self.api.AddPersonKey(person_id, key_fields)
715 self.api.BlacklistKey(key_id)
717 # Is effectively deleted
718 assert not self.api.GetKeys([key_id])
720 # Cannot be added again
722 key_id = self.api.AddPersonKey(person_id, key_fields)
728 print "Added key", key_id, "to user", person_id
730 def UpdateKeys(self):
732 Make random changes to any keys we may have added.
735 key_types = self.api.GetKeyTypes()
737 raise Exception, "No key types"
739 for key_id in self.key_ids:
741 key_fields = random_key(key_types)
742 self.api.UpdateKey(key_id, key_fields)
746 key = self.api.GetKeys([key_id])[0]
747 for field in key_fields:
748 assert key[field] == key_fields[field]
751 print "Updated key", key_id
753 def DeleteKeys(self):
755 Delete any random keys we may have added.
758 for key_id in self.key_ids:
759 self.api.DeleteKey(key_id)
762 assert not self.api.GetKeys([key_id])
765 print "Deleted key", key_id
768 assert not self.api.GetKeys(self.key_ids)
772 def AddNodeGroups(self, n = 10):
774 Add a number of random node groups.
779 nodegroup_fields = random_nodegroup()
780 nodegroup_id = self.api.AddNodeGroup(nodegroup_fields)
782 # Should return a unique nodegroup_id
783 assert nodegroup_id not in self.nodegroup_ids
784 self.nodegroup_ids.append(nodegroup_id)
788 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
789 for field in nodegroup_fields:
790 assert nodegroup[field] == nodegroup_fields[field]
793 print "Added node group", nodegroup_id
795 def UpdateNodeGroups(self):
797 Make random changes to any node groups we may have added.
800 for nodegroup_id in self.nodegroup_ids:
802 nodegroup_fields = random_nodegroup()
803 self.api.UpdateNodeGroup(nodegroup_id, nodegroup_fields)
807 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
808 for field in nodegroup_fields:
809 assert nodegroup[field] == nodegroup_fields[field]
812 print "Updated node group", nodegroup_id
814 def DeleteNodeGroups(self):
816 Delete any random node groups we may have added.
819 for nodegroup_id in self.nodegroup_ids:
820 self.api.DeleteNodeGroup(nodegroup_id)
823 assert not self.api.GetNodeGroups([nodegroup_id])
826 print "Deleted node group", nodegroup_id
829 assert not self.api.GetNodeGroups(self.nodegroup_ids)
831 self.nodegroup_ids = []
833 def AddNodes(self, per_site = 2):
835 Add a number of random nodes to each site. Each node will also
836 be added to a random node group if AddNodeGroups() was
840 boot_states = self.api.GetBootStates()
842 raise Exception, "No boot states"
844 for site_id in self.site_ids:
845 for i in range(per_site):
847 node_fields = random_node(boot_states)
848 node_id = self.api.AddNode(site_id, node_fields)
850 # Should return a unique node_id
851 assert node_id not in self.node_ids
852 self.node_ids.append(node_id)
854 # Add to a random set of node groups
855 nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
856 for nodegroup_id in nodegroup_ids:
857 self.api.AddNodeToNodeGroup(node_id, nodegroup_id)
861 node = self.api.GetNodes([node_id])[0]
862 for field in node_fields:
863 assert node[field] == node_fields[field]
866 print "Added node", node_id
868 def UpdateNodes(self):
870 Make random changes to any nodes we may have added.
873 boot_states = self.api.GetBootStates()
875 raise Exception, "No boot states"
877 for node_id in self.node_ids:
879 node_fields = random_node(boot_states)
880 self.api.UpdateNode(node_id, node_fields)
882 node = self.api.GetNodes([node_id])[0]
884 # Add to a random set of node groups
885 nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
886 for nodegroup_id in (set(nodegroup_ids) - set(node['nodegroup_ids'])):
887 self.api.AddNodeToNodeGroup(node_id, nodegroup_id)
888 for nodegroup_id in (set(node['nodegroup_ids']) - set(nodegroup_ids)):
889 self.api.DeleteNodeFromNodeGroup(node_id, nodegroup_id)
893 node = self.api.GetNodes([node_id])[0]
894 for field in node_fields:
895 assert node[field] == node_fields[field]
896 assert set(nodegroup_ids) == set(node['nodegroup_ids'])
899 print "Updated node", node_id
900 print "Added node", node_id, "to node groups", nodegroup_ids
902 def DeleteNodes(self):
904 Delete any random nodes we may have added.
907 for node_id in self.node_ids:
908 # Remove from node groups
909 node = self.api.GetNodes([node_id])[0]
910 for nodegroup_id in node['nodegroup_ids']:
911 self.api.DeleteNodeFromNodeGroup(node_id, nodegroup_id)
914 node = self.api.GetNodes([node_id])[0]
915 assert not node['nodegroup_ids']
917 self.api.DeleteNode(node_id)
920 assert not self.api.GetNodes([node_id])
923 print "Deleted node", node_id
926 assert not self.api.GetNodes(self.node_ids)
930 def AddNodeNetworks(self, per_node = 1):
932 Add a number of random network interfaces to each node.
935 network_methods = self.api.GetNetworkMethods()
936 if not network_methods:
937 raise Exception, "No network methods"
939 network_types = self.api.GetNetworkTypes()
940 if not network_types:
941 raise Exception, "No network types"
943 for node_id in self.node_ids:
944 for i in range(per_node):
945 method = random.sample(network_methods, 1)[0]
946 type = random.sample(network_types, 1)[0]
949 nodenetwork_fields = random_nodenetwork(method, type)
950 nodenetwork_id = self.api.AddNodeNetwork(node_id, nodenetwork_fields)
952 # Should return a unique nodenetwork_id
953 assert nodenetwork_id not in self.nodenetwork_ids
954 self.nodenetwork_ids.append(nodenetwork_id)
958 nodenetwork = self.api.GetNodeNetworks([nodenetwork_id])[0]
959 for field in nodenetwork_fields:
960 assert nodenetwork[field] == nodenetwork_fields[field]
963 print "Added node network", nodenetwork_id, "to node", node_id
965 def UpdateNodeNetworks(self):
967 Make random changes to any network interfaces we may have added.
970 network_methods = self.api.GetNetworkMethods()
971 if not network_methods:
972 raise Exception, "No network methods"
974 network_types = self.api.GetNetworkTypes()
975 if not network_types:
976 raise Exception, "No network types"
978 for nodenetwork_id in self.nodenetwork_ids:
979 method = random.sample(network_methods, 1)[0]
980 type = random.sample(network_types, 1)[0]
983 nodenetwork_fields = random_nodenetwork(method, type)
984 self.api.UpdateNodeNetwork(nodenetwork_id, nodenetwork_fields)
988 nodenetwork = self.api.GetNodeNetworks([nodenetwork_id])[0]
989 for field in nodenetwork_fields:
990 assert nodenetwork[field] == nodenetwork_fields[field]
993 print "Updated node network", nodenetwork_id
995 def DeleteNodeNetworks(self):
997 Delete any random network interfaces we may have added.
1000 for nodenetwork_id in self.nodenetwork_ids:
1001 self.api.DeleteNodeNetwork(nodenetwork_id)
1004 assert not self.api.GetNodeNetworks([nodenetwork_id])
1007 print "Deleted node network", nodenetwork_id
1010 assert not self.api.GetNodeNetworks(self.nodenetwork_ids)
1012 self.nodenetwork_ids = []
1014 def AddPCUs(self, per_site = 1):
1016 Add a number of random PCUs to each site. Each node at the
1017 site will be added to a port on the PCU if AddNodes() was
1021 for site_id in self.site_ids:
1022 for i in range(per_site):
1024 pcu_fields = random_pcu()
1025 pcu_id = self.api.AddPCU(site_id, pcu_fields)
1027 # Should return a unique pcu_id
1028 assert pcu_id not in self.pcu_ids
1029 self.pcu_ids.append(pcu_id)
1031 # Add each node at this site to a different port on this PCU
1032 site = self.api.GetSites([site_id])[0]
1033 port = randint(1, 10)
1034 for node_id in site['node_ids']:
1035 self.api.AddNodeToPCU(node_id, pcu_id, port)
1040 pcu = self.api.GetPCUs([pcu_id])[0]
1041 for field in pcu_fields:
1042 assert pcu[field] == pcu_fields[field]
1045 print "Added PCU", pcu_id, "to site", site_id
1047 def UpdatePCUs(self):
1049 Make random changes to any PCUs we may have added.
1052 for pcu_id in self.pcu_ids:
1054 pcu_fields = random_pcu()
1055 self.api.UpdatePCU(pcu_id, pcu_fields)
1059 pcu = self.api.GetPCUs([pcu_id])[0]
1060 for field in pcu_fields:
1061 assert pcu[field] == pcu_fields[field]
1064 print "Updated PCU", pcu_id
1066 def DeletePCUs(self):
1068 Delete any random nodes we may have added.
1071 for pcu_id in self.pcu_ids:
1072 # Remove nodes from PCU
1073 pcu = self.api.GetPCUs([pcu_id])[0]
1074 for node_id in pcu['node_ids']:
1075 self.api.DeleteNodeFromPCU(node_id, pcu_id)
1078 pcu = self.api.GetPCUs([pcu_id])[0]
1079 assert not pcu['node_ids']
1081 self.api.DeletePCU(pcu_id)
1084 assert not self.api.GetPCUs([pcu_id])
1087 print "Deleted PCU", pcu_id
1090 assert not self.api.GetPCUs(self.pcu_ids)
1094 def AddConfFiles(self, n = 10):
1096 Add a number of random global configuration files.
1102 # Add a random configuration file
1103 conf_files.append(random_conf_file())
1106 # Add a nodegroup override file
1107 nodegroup_conf_file = conf_files[0].copy()
1108 nodegroup_conf_file['source'] = randpath(255)
1109 conf_files.append(nodegroup_conf_file)
1111 # Add a node override file
1112 node_conf_file = conf_files[0].copy()
1113 node_conf_file['source'] = randpath(255)
1114 conf_files.append(node_conf_file)
1116 for conf_file_fields in conf_files:
1117 conf_file_id = self.api.AddConfFile(conf_file_fields)
1119 # Should return a unique conf_file_id
1120 assert conf_file_id not in self.conf_file_ids
1121 self.conf_file_ids.append(conf_file_id)
1124 if conf_file_fields == nodegroup_conf_file and self.nodegroup_ids:
1125 nodegroup_id = random.sample(self.nodegroup_ids, 1)[0]
1126 self.api.AddConfFileToNodeGroup(conf_file_id, nodegroup_id)
1131 if conf_file_fields == node_conf_file and self.node_ids:
1132 node_id = random.sample(self.node_ids, 1)[0]
1133 self.api.AddConfFileToNode(conf_file_id, node_id)
1138 # Check configuration file
1139 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1140 for field in conf_file_fields:
1141 assert conf_file[field] == conf_file_fields[field]
1144 print "Added configuration file", conf_file_id,
1145 if nodegroup_id is not None:
1146 print "to node group", nodegroup_id,
1147 elif node_id is not None:
1148 print "to node", node_id,
1151 def UpdateConfFiles(self):
1153 Make random changes to any configuration files we may have added.
1156 for conf_file_id in self.conf_file_ids:
1157 # Update configuration file
1158 conf_file_fields = random_conf_file()
1159 # Do not update dest so that it remains an override if set
1160 if 'dest' in conf_file_fields:
1161 del conf_file_fields['dest']
1162 self.api.UpdateConfFile(conf_file_id, conf_file_fields)
1165 # Check configuration file
1166 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1167 for field in conf_file_fields:
1168 assert conf_file[field] == conf_file_fields[field]
1171 print "Updated configuration file", conf_file_id
1173 def DeleteConfFiles(self):
1175 Delete any random configuration files we may have added.
1178 for conf_file_id in self.conf_file_ids:
1179 self.api.DeleteConfFile(conf_file_id)
1182 assert not self.api.GetConfFiles([conf_file_id])
1185 print "Deleted configuration file", conf_file_id
1188 assert not self.api.GetConfFiles(self.conf_file_ids)
1190 self.conf_file_ids = []
1192 def AddSliceAttributeTypes(self, n = 10):
1194 Add a number of random slice attribute types.
1197 roles = self.api.GetRoles()
1199 raise Exception, "No roles"
1200 role_ids = [role['role_id'] for role in roles]
1203 attribute_type_fields = random_attribute_type(role_ids)
1204 attribute_type_id = self.api.AddSliceAttributeType(attribute_type_fields)
1206 # Should return a unique attribute_type_id
1207 assert attribute_type_id not in self.attribute_type_ids
1208 self.attribute_type_ids.append(attribute_type_id)
1211 # Check slice attribute type
1212 attribute_type = self.api.GetSliceAttributeTypes([attribute_type_id])[0]
1213 for field in attribute_type_fields:
1214 assert attribute_type[field] == attribute_type_fields[field]
1217 print "Added slice attribute type", attribute_type_id
1219 def UpdateSliceAttributeTypes(self):
1221 Make random changes to any slice attribute types we may have added.
1224 roles = self.api.GetRoles()
1226 raise Exception, "No roles"
1227 role_ids = [role['role_id'] for role in roles]
1229 for attribute_type_id in self.attribute_type_ids:
1230 # Update slice attribute type
1231 attribute_type_fields = random_attribute_type(role_ids)
1232 self.api.UpdateSliceAttributeType(attribute_type_id, attribute_type_fields)
1235 # Check slice attribute type
1236 attribute_type = self.api.GetSliceAttributeTypes([attribute_type_id])[0]
1237 for field in attribute_type_fields:
1238 assert attribute_type[field] == attribute_type_fields[field]
1241 print "Updated slice attribute type", attribute_type_id
1243 def DeleteSliceAttributeTypes(self):
1245 Delete any random slice attribute types we may have added.
1248 for attribute_type_id in self.attribute_type_ids:
1249 self.api.DeleteSliceAttributeType(attribute_type_id)
1252 assert not self.api.GetSliceAttributeTypes([attribute_type_id])
1255 print "Deleted slice attribute type", attribute_type_id
1258 assert not self.api.GetSliceAttributeTypes(self.attribute_type_ids)
1260 self.attribute_type_ids = []
1262 def AddSlices(self, per_site = 10):
1264 Add a number of random slices per site.
1267 for site in self.api.GetSites(self.site_ids):
1268 for i in range(min(per_site, site['max_slices'])):
1270 slice_fields = random_slice(site['login_base'])
1271 slice_id = self.api.AddSlice(slice_fields)
1273 # Should return a unique slice_id
1274 assert slice_id not in self.slice_ids
1275 self.slice_ids.append(slice_id)
1277 # Add slice to a random set of nodes
1278 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1280 self.api.AddSliceToNodes(slice_id, node_ids)
1282 # Add random set of site users to slice
1283 person_ids = random.sample(site['person_ids'], randint(0, len(site['person_ids'])))
1284 for person_id in person_ids:
1285 self.api.AddPersonToSlice(person_id, slice_id)
1289 slice = self.api.GetSlices([slice_id])[0]
1290 for field in slice_fields:
1291 assert slice[field] == slice_fields[field]
1293 assert set(node_ids) == set(slice['node_ids'])
1294 assert set(person_ids) == set(slice['person_ids'])
1297 print "Added slice", slice_id, "to site", site['site_id'],
1299 print "and nodes", node_ids,
1302 print "Added users", site['person_ids'], "to slice", slice_id
1304 def UpdateSlices(self):
1306 Make random changes to any slices we may have added.
1309 for slice_id in self.slice_ids:
1311 slice_fields = random_slice("unused")
1312 # Cannot change slice name
1313 if 'name' in slice_fields:
1314 del slice_fields['name']
1315 self.api.UpdateSlice(slice_id, slice_fields)
1317 slice = self.api.GetSlices([slice_id])[0]
1319 # Add slice to a random set of nodes
1320 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1321 self.api.AddSliceToNodes(slice_id, list(set(node_ids) - set(slice['node_ids'])))
1322 self.api.DeleteSliceFromNodes(slice_id, list(set(slice['node_ids']) - set(node_ids)))
1324 # Add random set of users to slice
1325 person_ids = random.sample(self.person_ids, randint(0, len(self.person_ids)))
1326 for person_id in (set(person_ids) - set(slice['person_ids'])):
1327 self.api.AddPersonToSlice(person_id, slice_id)
1328 for person_id in (set(slice['person_ids']) - set(person_ids)):
1329 self.api.DeletePersonFromSlice(person_id, slice_id)
1332 slice = self.api.GetSlices([slice_id])[0]
1333 for field in slice_fields:
1334 assert slice[field] == slice_fields[field]
1335 assert set(node_ids) == set(slice['node_ids'])
1336 assert set(person_ids) == set(slice['person_ids'])
1339 print "Updated slice", slice_id
1340 print "Added nodes", node_ids, "to slice", slice_id
1341 print "Added persons", person_ids, "to slice", slice_id
1343 def DeleteSlices(self):
1345 Delete any random slices we may have added.
1348 for slice_id in self.slice_ids:
1349 self.api.DeleteSlice(slice_id)
1352 assert not self.api.GetSlices([slice_id])
1355 print "Deleted slice", slice_id
1358 assert not self.api.GetSlices(self.slice_ids)
1362 def AddSliceAttributes(self, per_slice = 2):
1364 Add a number of random slices per site.
1367 if not self.attribute_type_ids:
1370 for slice_id in self.slice_ids:
1371 slice = self.api.GetSlices([slice_id])[0]
1373 for i in range(per_slice):
1374 # Set a random slice/sliver attribute
1375 for attribute_type_id in random.sample(self.attribute_type_ids, 1):
1376 value = randstr(16, letters + '_' + digits)
1377 # Make it a sliver attribute with 50% probability
1378 if slice['node_ids']:
1379 node_id = random.sample(slice['node_ids'] + [None] * len(slice['node_ids']), 1)[0]
1383 # Add slice attribute
1385 slice_attribute_id = self.api.AddSliceAttribute(slice_id, attribute_type_id, value)
1387 slice_attribute_id = self.api.AddSliceAttribute(slice_id, attribute_type_id, value, node_id)
1389 # Should return a unique slice_attribute_id
1390 assert slice_attribute_id not in self.slice_attribute_ids
1391 self.slice_attribute_ids.append(slice_attribute_id)
1394 # Check slice attribute
1395 slice_attribute = self.api.GetSliceAttributes([slice_attribute_id])[0]
1396 for field in 'attribute_type_id', 'slice_id', 'node_id', 'slice_attribute_id', 'value':
1397 assert slice_attribute[field] == locals()[field]
1400 print "Added slice attribute", slice_attribute_id, "of type", attribute_type_id,
1401 if node_id is not None:
1402 print "to node", node_id,
1405 def UpdateSliceAttributes(self):
1407 Make random changes to any slice attributes we may have added.
1410 for slice_attribute_id in self.slice_attribute_ids:
1411 # Update slice attribute
1412 value = randstr(16, letters + '_' + digits)
1413 self.api.UpdateSliceAttribute(slice_attribute_id, value)
1415 # Check slice attribute again
1416 slice_attribute = self.api.GetSliceAttributes([slice_attribute_id])[0]
1417 assert slice_attribute['value'] == value
1420 print "Updated slice attribute", slice_attribute_id
1422 def DeleteSliceAttributes(self):
1424 Delete any random slice attributes we may have added.
1427 for slice_attribute_id in self.slice_attribute_ids:
1428 self.api.DeleteSliceAttribute(slice_attribute_id)
1431 assert not self.api.GetSliceAttributes([slice_attribute_id])
1434 print "Deleted slice attribute", slice_attribute_id
1437 assert not self.api.GetSliceAttributes(self.slice_attribute_ids)
1439 self.slice_attribute_ids = []
1442 parser = OptionParser()
1443 parser.add_option("-c", "--check", action = "store_true", default = False, help = "Check most actions (default: %default)")
1444 parser.add_option("-q", "--quiet", action = "store_true", default = False, help = "Be quiet (default: %default)")
1445 parser.add_option("-t", "--tiny", action = "store_true", default = False, help = "Run a tiny test (default: %default)")
1446 (options, args) = parser.parse_args()
1448 test = Test(api = Shell(),
1449 check = options.check,
1450 verbose = not options.quiet)
1455 params = Test.default
1459 if __name__ == "__main__":