3 # Test script utility class
5 # Mark Huang <mlhuang@cs.princeton.edu>
6 # Copyright (C) 2006 The Trustees of Princeton University
8 # $Id: plcsh-stress-test.py 9505 2008-05-30 14:02:27Z thierry $
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_interface(method, type):
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 interface_fields[field] = socket.inet_ntoa(struct.pack('>L', locals()[field]))
170 return interface_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 'interfaces_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,
235 # we're using a single tag so a given node can only be in a single nodegroup
238 'interfaces_per_node': 1,
241 'attribute_types': 10,
242 'slices_per_site': 10,
243 'attributes_per_slice': 2,
246 def __init__(self, api, check = True, verbose = True):
249 self.verbose = verbose
252 self.address_type_ids = []
253 self.address_ids = []
256 self.nodegroup_ids = []
258 self.interface_ids = []
260 self.conf_file_ids = []
261 self.attribute_type_ids = []
263 self.slice_attribute_ids = []
265 def Run(self, **kwds):
267 Run a complete database and API consistency test. Populates
268 the database with a set of random entities, updates them, then
269 deletes them. Examples:
271 test.Run() # Defaults
272 test.Run(**Test.default) # Defaults
273 test.Run(**Test.tiny) # Tiny set
274 test.Run(sites = 123, slices_per_site = 4) # Defaults with overrides
281 def Add(self, **kwds):
283 Populate the database with a set of random entities. Examples:
285 test.populate() # Defaults
286 test.populate(Test.tiny) # Tiny set
287 test.populate(sites = 123, slices_per_site = 4) # Defaults with overrides
290 params = self.default.copy()
293 self.AddSites(params['sites'])
294 self.AddAddressTypes(params['address_types'])
295 self.AddAddresses(params['addresses_per_site'])
296 self.AddPersons(params['persons_per_site'])
297 self.AddKeys(params['keys_per_person'])
298 self.AddNodeGroups(params['nodegroups'])
299 self.AddNodes(params['nodes_per_site'])
300 self.AddInterfaces(params['interfaces_per_node'])
301 self.AddPCUs(params['pcus_per_site'])
302 self.AddConfFiles(params['conf_files'])
303 self.AddSliceAttributeTypes(params['attribute_types'])
304 self.AddSlices(params['slices_per_site'])
305 self.AddSliceAttributes(params['attributes_per_slice'])
309 self.UpdateAddressTypes()
310 self.UpdateAddresses()
313 self.UpdateNodeGroups()
315 self.UpdateInterfaces()
317 self.UpdateConfFiles()
318 self.UpdateSliceAttributeTypes()
320 self.UpdateSliceAttributes()
323 self.DeleteSliceAttributes()
325 self.DeleteSliceAttributeTypes()
327 self.DeleteConfFiles()
329 self.DeleteInterfaces()
332 self.DeleteNodeGroups()
333 self.DeleteAddresses()
334 self.DeleteAddressTypes()
337 def AddSites(self, n = 10):
339 Add a number of random sites.
344 site_fields = random_site()
345 site_id = self.api.AddSite(site_fields)
347 # Should return a unique site_id
348 assert site_id not in self.site_ids
349 self.site_ids.append(site_id)
351 # Enable slice creation
352 site_fields['max_slices'] = randint(1, 10)
353 self.api.UpdateSite(site_id, site_fields)
357 site = self.api.GetSites([site_id])[0]
358 for field in site_fields:
359 assert site[field] == site_fields[field]
362 print "Added site", site_id
364 def UpdateSites(self):
366 Make random changes to any sites we may have added.
369 for site_id in self.site_ids:
371 site_fields = random_site()
372 # Do not change login_base
373 if 'login_base' in site_fields:
374 del site_fields['login_base']
375 self.api.UpdateSite(site_id, site_fields)
379 site = self.api.GetSites([site_id])[0]
380 for field in site_fields:
381 assert site[field] == site_fields[field]
384 print "Updated site", site_id
386 def DeleteSites(self):
388 Delete any random sites we may have added.
391 for site_id in self.site_ids:
392 self.api.DeleteSite(site_id)
395 assert not self.api.GetSites([site_id])
398 print "Deleted site", site_id
401 assert not self.api.GetSites(self.site_ids)
405 def AddAddressTypes(self, n = 2):
407 Add a number of random address types.
411 address_type_fields = random_address_type()
412 address_type_id = self.api.AddAddressType(address_type_fields)
414 # Should return a unique address_type_id
415 assert address_type_id not in self.address_type_ids
416 self.address_type_ids.append(address_type_id)
420 address_type = self.api.GetAddressTypes([address_type_id])[0]
421 for field in address_type_fields:
422 assert address_type[field] == address_type_fields[field]
425 print "Added address type", address_type_id
427 def UpdateAddressTypes(self):
429 Make random changes to any address types we may have added.
432 for address_type_id in self.address_type_ids:
433 # Update address_type
434 address_type_fields = random_address_type()
435 self.api.UpdateAddressType(address_type_id, address_type_fields)
439 address_type = self.api.GetAddressTypes([address_type_id])[0]
440 for field in address_type_fields:
441 assert address_type[field] == address_type_fields[field]
444 print "Updated address_type", address_type_id
446 def DeleteAddressTypes(self):
448 Delete any random address types we may have added.
451 for address_type_id in self.address_type_ids:
452 self.api.DeleteAddressType(address_type_id)
455 assert not self.api.GetAddressTypes([address_type_id])
458 print "Deleted address type", address_type_id
461 assert not self.api.GetAddressTypes(self.address_type_ids)
463 self.address_type_ids = []
465 def AddAddresses(self, per_site = 2):
467 Add a number of random addresses to each site.
470 for site_id in self.site_ids:
471 for i in range(per_site):
472 address_fields = random_address()
473 address_id = self.api.AddSiteAddress(site_id, address_fields)
475 # Should return a unique address_id
476 assert address_id not in self.address_ids
477 self.address_ids.append(address_id)
479 # Add random address type
480 if self.address_type_ids:
481 for address_type_id in random.sample(self.address_type_ids, 1):
482 self.api.AddAddressTypeToAddress(address_type_id, address_id)
486 address = self.api.GetAddresses([address_id])[0]
487 for field in address_fields:
488 assert address[field] == address_fields[field]
491 print "Added address", address_id, "to site", site_id
493 def UpdateAddresses(self):
495 Make random changes to any addresses we may have added.
498 for address_id in self.address_ids:
500 address_fields = random_address()
501 self.api.UpdateAddress(address_id, address_fields)
505 address = self.api.GetAddresses([address_id])[0]
506 for field in address_fields:
507 assert address[field] == address_fields[field]
510 print "Updated address", address_id
512 def DeleteAddresses(self):
514 Delete any random addresses we may have added.
517 for address_id in self.address_ids:
518 # Remove address types
519 address = self.api.GetAddresses([address_id])[0]
520 for address_type_id in address['address_type_ids']:
521 self.api.DeleteAddressTypeFromAddress(address_type_id, address_id)
524 address = self.api.GetAddresses([address_id])[0]
525 assert not address['address_type_ids']
527 self.api.DeleteAddress(address_id)
530 assert not self.api.GetAddresses([address_id])
533 print "Deleted address", address_id
536 assert not self.api.GetAddresses(self.address_ids)
538 self.address_ids = []
540 def AddPersons(self, per_site = 10):
542 Add a number of random users to each site.
545 for site_id in self.site_ids:
546 for i in range(per_site):
548 person_fields = random_person()
549 person_id = self.api.AddPerson(person_fields)
551 # Should return a unique person_id
552 assert person_id not in self.person_ids
553 self.person_ids.append(person_id)
557 person = self.api.GetPersons([person_id])[0]
558 for field in person_fields:
559 if field != 'password':
560 assert person[field] == person_fields[field]
562 auth = {'AuthMethod': "password",
563 'Username': person_fields['email'],
564 'AuthString': person_fields['password']}
567 # Check that user is disabled
569 assert not self.api.AuthCheck(auth)
573 # Add random set of roles
574 role_ids = random.sample([20, 30, 40], randint(1, 3))
575 for role_id in role_ids:
576 self.api.AddRoleToPerson(role_id, person_id)
579 person = self.api.GetPersons([person_id])[0]
580 assert set(role_ids) == set(person['role_ids'])
583 self.api.UpdatePerson(person_id, {'enabled': True})
586 # Check that user is enabled
587 assert self.api.AuthCheck(auth)
589 # Associate user with site
590 self.api.AddPersonToSite(person_id, site_id)
591 self.api.SetPersonPrimarySite(person_id, site_id)
594 person = self.api.GetPersons([person_id])[0]
595 assert person['site_ids'][0] == site_id
598 print "Added user", person_id, "to site", site_id
600 def UpdatePersons(self):
602 Make random changes to any users we may have added.
605 for person_id in self.person_ids:
607 person_fields = random_person()
609 person_fields['enabled'] = True
610 self.api.UpdatePerson(person_id, person_fields)
614 person = self.api.GetPersons([person_id])[0]
615 for field in person_fields:
616 if field != 'password':
617 assert person[field] == person_fields[field]
620 print "Updated person", person_id
622 person = self.api.GetPersons([person_id])[0]
624 # Associate user with a random set of sites
625 site_ids = random.sample(self.site_ids, randint(0, len(self.site_ids)))
626 for site_id in (set(site_ids) - set(person['site_ids'])):
627 self.api.AddPersonToSite(person_id, site_id)
628 for site_id in (set(person['site_ids']) - set(site_ids)):
629 self.api.DeletePersonFromSite(person_id, site_id)
632 self.api.SetPersonPrimarySite(person_id, site_ids[0])
635 person = self.api.GetPersons([person_id])[0]
636 assert set(site_ids) == set(person['site_ids'])
639 print "Updated person", person_id, "to sites", site_ids
641 def DeletePersons(self):
643 Delete any random users we may have added.
646 for person_id in self.person_ids:
648 person = self.api.GetPersons([person_id])[0]
649 for site_id in person['site_ids']:
650 self.api.DeletePersonFromSite(person_id, site_id)
653 person = self.api.GetPersons([person_id])[0]
654 assert not person['site_ids']
657 for role_id in person['role_ids']:
658 self.api.DeleteRoleFromPerson(role_id, person_id)
661 person = self.api.GetPersons([person_id])[0]
662 assert not person['role_ids']
665 self.api.UpdatePerson(person_id, {'enabled': False})
668 person = self.api.GetPersons([person_id])[0]
669 assert not person['enabled']
672 self.api.DeletePerson(person_id)
675 assert not self.api.GetPersons([person_id])
678 print "Deleted user", person_id
681 assert not self.api.GetPersons(self.person_ids)
685 def AddKeys(self, per_person = 2):
687 Add a number of random keys to each user.
690 key_types = self.api.GetKeyTypes()
692 raise Exception, "No key types"
694 for person_id in self.person_ids:
695 for i in range(per_person):
697 key_fields = random_key(key_types)
698 key_id = self.api.AddPersonKey(person_id, key_fields)
700 # Should return a unique key_id
701 assert key_id not in self.key_ids
702 self.key_ids.append(key_id)
706 key = self.api.GetKeys([key_id])[0]
707 for field in key_fields:
708 assert key[field] == key_fields[field]
710 # Add and immediately blacklist a key
711 key_fields = random_key(key_types)
712 key_id = self.api.AddPersonKey(person_id, key_fields)
714 self.api.BlacklistKey(key_id)
716 # Is effectively deleted
717 assert not self.api.GetKeys([key_id])
719 # Cannot be added again
721 key_id = self.api.AddPersonKey(person_id, key_fields)
727 print "Added key", key_id, "to user", person_id
729 def UpdateKeys(self):
731 Make random changes to any keys we may have added.
734 key_types = self.api.GetKeyTypes()
736 raise Exception, "No key types"
738 for key_id in self.key_ids:
740 key_fields = random_key(key_types)
741 self.api.UpdateKey(key_id, key_fields)
745 key = self.api.GetKeys([key_id])[0]
746 for field in key_fields:
747 assert key[field] == key_fields[field]
750 print "Updated key", key_id
752 def DeleteKeys(self):
754 Delete any random keys we may have added.
757 for key_id in self.key_ids:
758 self.api.DeleteKey(key_id)
761 assert not self.api.GetKeys([key_id])
764 print "Deleted key", key_id
767 assert not self.api.GetKeys(self.key_ids)
771 # this assumes the default node tag types in db-config are visible
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:
801 nodegroup_fields = random_nodegroup()
802 self.api.UpdateNodeGroup(nodegroup_id, nodegroup_fields)
806 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
807 for field in nodegroup_fields:
808 assert nodegroup[field] == nodegroup_fields[field]
811 print "Updated node group", nodegroup_id
813 def DeleteNodeGroups(self):
815 Delete any random node groups we may have added.
818 for nodegroup_id in self.nodegroup_ids:
819 self.api.DeleteNodeGroup(nodegroup_id)
822 assert not self.api.GetNodeGroups([nodegroup_id])
825 print "Deleted node group", nodegroup_id
828 assert not self.api.GetNodeGroups(self.nodegroup_ids)
830 self.nodegroup_ids = []
832 def AddNodes(self, per_site = 2):
834 Add a number of random nodes to each site. Each node will also
835 be added to a random node group if AddNodeGroups() was
839 boot_states = self.api.GetBootStates()
841 raise Exception, "No boot states"
843 for site_id in self.site_ids:
844 for i in range(per_site):
846 node_fields = random_node(boot_states)
847 node_id = self.api.AddNode(site_id, node_fields)
849 # Should return a unique node_id
850 assert node_id not in self.node_ids
851 self.node_ids.append(node_id)
853 # Add to a random set of node groups
854 nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
855 for nodegroup_id in nodegroup_ids:
856 self.api.AddNodeToNodeGroup(node_id, nodegroup_id)
860 node = self.api.GetNodes([node_id])[0]
861 for field in node_fields:
862 assert node[field] == node_fields[field]
865 print "Added node", node_id
867 def UpdateNodes(self):
869 Make random changes to any nodes we may have added.
872 boot_states = self.api.GetBootStates()
874 raise Exception, "No boot states"
876 for node_id in self.node_ids:
878 node_fields = random_node(boot_states)
879 self.api.UpdateNode(node_id, node_fields)
881 node = self.api.GetNodes([node_id])[0]
883 # Add to a random set of node groups
884 nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
885 for nodegroup_id in (set(nodegroup_ids) - set(node['nodegroup_ids'])):
886 self.api.AddNodeToNodeGroup(node_id, nodegroup_id)
887 for nodegroup_id in (set(node['nodegroup_ids']) - set(nodegroup_ids)):
888 self.api.DeleteNodeFromNodeGroup(node_id, nodegroup_id)
892 node = self.api.GetNodes([node_id])[0]
893 for field in node_fields:
894 assert node[field] == node_fields[field]
895 assert set(nodegroup_ids) == set(node['nodegroup_ids'])
898 print "Updated node", node_id
899 print "Added node", node_id, "to node groups", nodegroup_ids
901 def DeleteNodes(self):
903 Delete any random nodes we may have added.
906 for node_id in self.node_ids:
907 # Remove from node groups
908 node = self.api.GetNodes([node_id])[0]
909 for nodegroup_id in node['nodegroup_ids']:
910 self.api.DeleteNodeFromNodeGroup(node_id, nodegroup_id)
913 node = self.api.GetNodes([node_id])[0]
914 assert not node['nodegroup_ids']
916 self.api.DeleteNode(node_id)
919 assert not self.api.GetNodes([node_id])
922 print "Deleted node", node_id
925 assert not self.api.GetNodes(self.node_ids)
929 def AddInterfaces(self, per_node = 1):
931 Add a number of random network interfaces to each node.
934 network_methods = self.api.GetNetworkMethods()
935 if not network_methods:
936 raise Exception, "No network methods"
938 network_types = self.api.GetNetworkTypes()
939 if not network_types:
940 raise Exception, "No network types"
942 for node_id in self.node_ids:
943 for i in range(per_node):
944 method = random.sample(network_methods, 1)[0]
945 type = random.sample(network_types, 1)[0]
948 interface_fields = random_interface(method, type)
949 interface_id = self.api.AddNodeNetwork(node_id, interface_fields)
951 # Should return a unique interface_id
952 assert interface_id not in self.interface_ids
953 self.interface_ids.append(interface_id)
957 interface = self.api.GetInterfaces([interface_id])[0]
958 for field in interface_fields:
959 assert interface[field] == interface_fields[field]
962 print "Added node network", interface_id, "to node", node_id
964 def UpdateInterfaces(self):
966 Make random changes to any network interfaces we may have added.
969 network_methods = self.api.GetNetworkMethods()
970 if not network_methods:
971 raise Exception, "No network methods"
973 network_types = self.api.GetNetworkTypes()
974 if not network_types:
975 raise Exception, "No network types"
977 for interface_id in self.interface_ids:
978 method = random.sample(network_methods, 1)[0]
979 type = random.sample(network_types, 1)[0]
982 interface_fields = random_interface(method, type)
983 self.api.UpdateNodeNetwork(interface_id, interface_fields)
987 interface = self.api.GetInterfaces([interface_id])[0]
988 for field in interface_fields:
989 assert interface[field] == interface_fields[field]
992 print "Updated node network", interface_id
994 def DeleteInterfaces(self):
996 Delete any random network interfaces we may have added.
999 for interface_id in self.interface_ids:
1000 self.api.DeleteNodeNetwork(interface_id)
1003 assert not self.api.GetInterfaces([interface_id])
1006 print "Deleted node network", interface_id
1009 assert not self.api.GetInterfaces(self.interface_ids)
1011 self.interface_ids = []
1013 def AddPCUs(self, per_site = 1):
1015 Add a number of random PCUs to each site. Each node at the
1016 site will be added to a port on the PCU if AddNodes() was
1020 for site_id in self.site_ids:
1021 for i in range(per_site):
1023 pcu_fields = random_pcu()
1024 pcu_id = self.api.AddPCU(site_id, pcu_fields)
1026 # Should return a unique pcu_id
1027 assert pcu_id not in self.pcu_ids
1028 self.pcu_ids.append(pcu_id)
1030 # Add each node at this site to a different port on this PCU
1031 site = self.api.GetSites([site_id])[0]
1032 port = randint(1, 10)
1033 for node_id in site['node_ids']:
1034 self.api.AddNodeToPCU(node_id, pcu_id, port)
1039 pcu = self.api.GetPCUs([pcu_id])[0]
1040 for field in pcu_fields:
1041 assert pcu[field] == pcu_fields[field]
1044 print "Added PCU", pcu_id, "to site", site_id
1046 def UpdatePCUs(self):
1048 Make random changes to any PCUs we may have added.
1051 for pcu_id in self.pcu_ids:
1053 pcu_fields = random_pcu()
1054 self.api.UpdatePCU(pcu_id, pcu_fields)
1058 pcu = self.api.GetPCUs([pcu_id])[0]
1059 for field in pcu_fields:
1060 assert pcu[field] == pcu_fields[field]
1063 print "Updated PCU", pcu_id
1065 def DeletePCUs(self):
1067 Delete any random nodes we may have added.
1070 for pcu_id in self.pcu_ids:
1071 # Remove nodes from PCU
1072 pcu = self.api.GetPCUs([pcu_id])[0]
1073 for node_id in pcu['node_ids']:
1074 self.api.DeleteNodeFromPCU(node_id, pcu_id)
1077 pcu = self.api.GetPCUs([pcu_id])[0]
1078 assert not pcu['node_ids']
1080 self.api.DeletePCU(pcu_id)
1083 assert not self.api.GetPCUs([pcu_id])
1086 print "Deleted PCU", pcu_id
1089 assert not self.api.GetPCUs(self.pcu_ids)
1093 def AddConfFiles(self, n = 10):
1095 Add a number of random global configuration files.
1101 # Add a random configuration file
1102 conf_files.append(random_conf_file())
1105 # Add a nodegroup override file
1106 nodegroup_conf_file = conf_files[0].copy()
1107 nodegroup_conf_file['source'] = randpath(255)
1108 conf_files.append(nodegroup_conf_file)
1110 # Add a node override file
1111 node_conf_file = conf_files[0].copy()
1112 node_conf_file['source'] = randpath(255)
1113 conf_files.append(node_conf_file)
1115 for conf_file_fields in conf_files:
1116 conf_file_id = self.api.AddConfFile(conf_file_fields)
1118 # Should return a unique conf_file_id
1119 assert conf_file_id not in self.conf_file_ids
1120 self.conf_file_ids.append(conf_file_id)
1123 if conf_file_fields == nodegroup_conf_file and self.nodegroup_ids:
1124 nodegroup_id = random.sample(self.nodegroup_ids, 1)[0]
1125 self.api.AddConfFileToNodeGroup(conf_file_id, nodegroup_id)
1130 if conf_file_fields == node_conf_file and self.node_ids:
1131 node_id = random.sample(self.node_ids, 1)[0]
1132 self.api.AddConfFileToNode(conf_file_id, node_id)
1137 # Check configuration file
1138 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1139 for field in conf_file_fields:
1140 assert conf_file[field] == conf_file_fields[field]
1143 print "Added configuration file", conf_file_id,
1144 if nodegroup_id is not None:
1145 print "to node group", nodegroup_id,
1146 elif node_id is not None:
1147 print "to node", node_id,
1150 def UpdateConfFiles(self):
1152 Make random changes to any configuration files we may have added.
1155 for conf_file_id in self.conf_file_ids:
1156 # Update configuration file
1157 conf_file_fields = random_conf_file()
1158 # Do not update dest so that it remains an override if set
1159 if 'dest' in conf_file_fields:
1160 del conf_file_fields['dest']
1161 self.api.UpdateConfFile(conf_file_id, conf_file_fields)
1164 # Check configuration file
1165 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1166 for field in conf_file_fields:
1167 assert conf_file[field] == conf_file_fields[field]
1170 print "Updated configuration file", conf_file_id
1172 def DeleteConfFiles(self):
1174 Delete any random configuration files we may have added.
1177 for conf_file_id in self.conf_file_ids:
1178 self.api.DeleteConfFile(conf_file_id)
1181 assert not self.api.GetConfFiles([conf_file_id])
1184 print "Deleted configuration file", conf_file_id
1187 assert not self.api.GetConfFiles(self.conf_file_ids)
1189 self.conf_file_ids = []
1191 def AddSliceAttributeTypes(self, n = 10):
1193 Add a number of random slice attribute types.
1196 roles = self.api.GetRoles()
1198 raise Exception, "No roles"
1199 role_ids = [role['role_id'] for role in roles]
1202 attribute_type_fields = random_attribute_type(role_ids)
1203 attribute_type_id = self.api.AddSliceAttributeType(attribute_type_fields)
1205 # Should return a unique attribute_type_id
1206 assert attribute_type_id not in self.attribute_type_ids
1207 self.attribute_type_ids.append(attribute_type_id)
1210 # Check slice attribute type
1211 attribute_type = self.api.GetSliceAttributeTypes([attribute_type_id])[0]
1212 for field in attribute_type_fields:
1213 assert attribute_type[field] == attribute_type_fields[field]
1216 print "Added slice attribute type", attribute_type_id
1218 def UpdateSliceAttributeTypes(self):
1220 Make random changes to any slice attribute types we may have added.
1223 roles = self.api.GetRoles()
1225 raise Exception, "No roles"
1226 role_ids = [role['role_id'] for role in roles]
1228 for attribute_type_id in self.attribute_type_ids:
1229 # Update slice attribute type
1230 attribute_type_fields = random_attribute_type(role_ids)
1231 self.api.UpdateSliceAttributeType(attribute_type_id, attribute_type_fields)
1234 # Check slice attribute type
1235 attribute_type = self.api.GetSliceAttributeTypes([attribute_type_id])[0]
1236 for field in attribute_type_fields:
1237 assert attribute_type[field] == attribute_type_fields[field]
1240 print "Updated slice attribute type", attribute_type_id
1242 def DeleteSliceAttributeTypes(self):
1244 Delete any random slice attribute types we may have added.
1247 for attribute_type_id in self.attribute_type_ids:
1248 self.api.DeleteSliceAttributeType(attribute_type_id)
1251 assert not self.api.GetSliceAttributeTypes([attribute_type_id])
1254 print "Deleted slice attribute type", attribute_type_id
1257 assert not self.api.GetSliceAttributeTypes(self.attribute_type_ids)
1259 self.attribute_type_ids = []
1261 def AddSlices(self, per_site = 10):
1263 Add a number of random slices per site.
1266 for site in self.api.GetSites(self.site_ids):
1267 for i in range(min(per_site, site['max_slices'])):
1269 slice_fields = random_slice(site['login_base'])
1270 slice_id = self.api.AddSlice(slice_fields)
1272 # Should return a unique slice_id
1273 assert slice_id not in self.slice_ids
1274 self.slice_ids.append(slice_id)
1276 # Add slice to a random set of nodes
1277 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1279 self.api.AddSliceToNodes(slice_id, node_ids)
1281 # Add random set of site users to slice
1282 person_ids = random.sample(site['person_ids'], randint(0, len(site['person_ids'])))
1283 for person_id in person_ids:
1284 self.api.AddPersonToSlice(person_id, slice_id)
1288 slice = self.api.GetSlices([slice_id])[0]
1289 for field in slice_fields:
1290 assert slice[field] == slice_fields[field]
1292 assert set(node_ids) == set(slice['node_ids'])
1293 assert set(person_ids) == set(slice['person_ids'])
1296 print "Added slice", slice_id, "to site", site['site_id'],
1298 print "and nodes", node_ids,
1301 print "Added users", site['person_ids'], "to slice", slice_id
1303 def UpdateSlices(self):
1305 Make random changes to any slices we may have added.
1308 for slice_id in self.slice_ids:
1310 slice_fields = random_slice("unused")
1311 # Cannot change slice name
1312 if 'name' in slice_fields:
1313 del slice_fields['name']
1314 self.api.UpdateSlice(slice_id, slice_fields)
1316 slice = self.api.GetSlices([slice_id])[0]
1318 # Add slice to a random set of nodes
1319 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1320 self.api.AddSliceToNodes(slice_id, list(set(node_ids) - set(slice['node_ids'])))
1321 self.api.DeleteSliceFromNodes(slice_id, list(set(slice['node_ids']) - set(node_ids)))
1323 # Add random set of users to slice
1324 person_ids = random.sample(self.person_ids, randint(0, len(self.person_ids)))
1325 for person_id in (set(person_ids) - set(slice['person_ids'])):
1326 self.api.AddPersonToSlice(person_id, slice_id)
1327 for person_id in (set(slice['person_ids']) - set(person_ids)):
1328 self.api.DeletePersonFromSlice(person_id, slice_id)
1331 slice = self.api.GetSlices([slice_id])[0]
1332 for field in slice_fields:
1333 assert slice[field] == slice_fields[field]
1334 assert set(node_ids) == set(slice['node_ids'])
1335 assert set(person_ids) == set(slice['person_ids'])
1338 print "Updated slice", slice_id
1339 print "Added nodes", node_ids, "to slice", slice_id
1340 print "Added persons", person_ids, "to slice", slice_id
1342 def DeleteSlices(self):
1344 Delete any random slices we may have added.
1347 for slice_id in self.slice_ids:
1348 self.api.DeleteSlice(slice_id)
1351 assert not self.api.GetSlices([slice_id])
1354 print "Deleted slice", slice_id
1357 assert not self.api.GetSlices(self.slice_ids)
1361 def AddSliceAttributes(self, per_slice = 2):
1363 Add a number of random slices per site.
1366 if not self.attribute_type_ids:
1369 for slice_id in self.slice_ids:
1370 slice = self.api.GetSlices([slice_id])[0]
1372 for i in range(per_slice):
1373 # Set a random slice/sliver attribute
1374 for attribute_type_id in random.sample(self.attribute_type_ids, 1):
1375 value = randstr(16, letters + '_' + digits)
1376 # Make it a sliver attribute with 50% probability
1377 if slice['node_ids']:
1378 node_id = random.sample(slice['node_ids'] + [None] * len(slice['node_ids']), 1)[0]
1382 # Add slice attribute
1384 slice_attribute_id = self.api.AddSliceAttribute(slice_id, attribute_type_id, value)
1386 slice_attribute_id = self.api.AddSliceAttribute(slice_id, attribute_type_id, value, node_id)
1388 # Should return a unique slice_attribute_id
1389 assert slice_attribute_id not in self.slice_attribute_ids
1390 self.slice_attribute_ids.append(slice_attribute_id)
1393 # Check slice attribute
1394 slice_attribute = self.api.GetSliceAttributes([slice_attribute_id])[0]
1395 for field in 'attribute_type_id', 'slice_id', 'node_id', 'slice_attribute_id', 'value':
1396 assert slice_attribute[field] == locals()[field]
1399 print "Added slice attribute", slice_attribute_id, "of type", attribute_type_id,
1400 if node_id is not None:
1401 print "to node", node_id,
1404 def UpdateSliceAttributes(self):
1406 Make random changes to any slice attributes we may have added.
1409 for slice_attribute_id in self.slice_attribute_ids:
1410 # Update slice attribute
1411 value = randstr(16, letters + '_' + digits)
1412 self.api.UpdateSliceAttribute(slice_attribute_id, value)
1414 # Check slice attribute again
1415 slice_attribute = self.api.GetSliceAttributes([slice_attribute_id])[0]
1416 assert slice_attribute['value'] == value
1419 print "Updated slice attribute", slice_attribute_id
1421 def DeleteSliceAttributes(self):
1423 Delete any random slice attributes we may have added.
1426 for slice_attribute_id in self.slice_attribute_ids:
1427 self.api.DeleteSliceAttribute(slice_attribute_id)
1430 assert not self.api.GetSliceAttributes([slice_attribute_id])
1433 print "Deleted slice attribute", slice_attribute_id
1436 assert not self.api.GetSliceAttributes(self.slice_attribute_ids)
1438 self.slice_attribute_ids = []
1441 parser = OptionParser()
1442 parser.add_option("-c", "--check", action = "store_true", default = False,
1443 help = "Check most actions (default: %default)")
1444 parser.add_option("-q", "--quiet", action = "store_true", default = False,
1445 help = "Be quiet (default: %default)")
1446 parser.add_option("-t", "--tiny", action = "store_true", default = False,
1447 help = "Run a tiny test (default: %default)")
1448 (options, args) = parser.parse_args()
1450 test = Test(api = Shell(),
1451 check = options.check,
1452 verbose = not options.quiet)
1457 params = Test.default
1461 if __name__ == "__main__":