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 nodegroups_tagname='deployment'
139 def random_nodegroup():
140 return (randstr(50), # groupname
141 nodegroups_tagname, # tagname
142 randstr(8), # tagvalue
145 def random_node(boot_states):
147 'hostname': randhostname(),
148 'boot_state': random.sample(boot_states, 1)[0],
149 'model': randstr(255),
150 'version': randstr(64),
153 def random_interface(method, type):
157 'bwlimit': randint(500000, 10000000),
161 ip = randint(0, 0xffffffff)
162 netmask = (0xffffffff << randint(2, 31)) & 0xffffffff
163 network = ip & netmask
164 broadcast = ((ip & netmask) | ~netmask) & 0xffffffff
165 gateway = randint(network + 1, broadcast - 1)
166 dns1 = randint(0, 0xffffffff)
168 for field in 'ip', 'netmask', 'network', 'broadcast', 'gateway', 'dns1':
169 interface_fields[field] = socket.inet_ntoa(struct.pack('>L', locals()[field]))
171 return interface_fields
175 'hostname': randhostname(),
176 'ip': socket.inet_ntoa(struct.pack('>L', randint(0, 0xffffffff))),
177 'protocol': randstr(16),
178 'username': randstr(254),
179 'password': randstr(254),
180 'notes': randstr(254),
181 'model': randstr(32),
184 def random_conf_file():
186 'enabled': bool(randint()),
187 'source': randpath(255),
188 'dest': randpath(255),
189 'file_permissions': "%#o" % randint(0, 512),
190 'file_owner': randstr(32, letters + '_' + digits),
191 'file_group': randstr(32, letters + '_' + digits),
192 'preinstall_cmd': randpath(100),
193 'postinstall_cmd': randpath(100),
194 'error_cmd': randpath(100),
195 'ignore_cmd_errors': bool(randint()),
196 'always_update': bool(randint()),
199 def random_attribute_type(role_ids):
201 'name': randstr(100),
202 'description': randstr(254),
203 'min_role_id': random.sample(role_ids, 1)[0],
206 def random_slice(login_base):
208 'name': login_base + "_" + randstr(11, letters).lower(),
209 'url': "http://" + randhostname() + "/",
210 'description': randstr(2048),
217 'addresses_per_site': 1,
218 'persons_per_site': 1,
219 'keys_per_person': 1,
222 'interfaces_per_node': 1,
225 'attribute_types': 1,
226 'slices_per_site': 1,
227 'attributes_per_slice': 1,
233 'addresses_per_site': 2,
234 'persons_per_site': 10,
235 'keys_per_person': 2,
236 # we're using a single tag so a given node can only be in a single nodegroup
239 'interfaces_per_node': 1,
242 'attribute_types': 10,
243 'slices_per_site': 10,
244 'attributes_per_slice': 2,
247 def __init__(self, api, check = True, verbose = True):
250 self.verbose = verbose
253 self.address_type_ids = []
254 self.address_ids = []
257 self.nodegroup_ids = []
259 self.interface_ids = []
261 self.conf_file_ids = []
262 self.attribute_type_ids = []
264 self.slice_attribute_ids = []
266 def Run(self, **kwds):
268 Run a complete database and API consistency test. Populates
269 the database with a set of random entities, updates them, then
270 deletes them. Examples:
272 test.Run() # Defaults
273 test.Run(**Test.default) # Defaults
274 test.Run(**Test.tiny) # Tiny set
275 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.AddInterfaces(params['interfaces_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.UpdateInterfaces()
318 self.UpdateConfFiles()
319 self.UpdateSliceAttributeTypes()
321 self.UpdateSliceAttributes()
324 self.DeleteSliceAttributes()
326 self.DeleteSliceAttributeTypes()
328 self.DeleteConfFiles()
330 self.DeleteInterfaces()
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 # this assumes the default node tag types in db-config are visible
773 def AddNodeGroups(self, n = 10):
775 Add a number of random node groups.
780 (groupname, tagname, tagvalue) = random_nodegroup()
781 nodegroup_id = self.api.AddNodeGroup(groupname, tagname, tagvalue)
783 # Should return a unique nodegroup_id
784 assert nodegroup_id not in self.nodegroup_ids
785 self.nodegroup_ids.append(nodegroup_id)
789 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
790 for field in nodegroup_fields:
791 assert nodegroup[field] == nodegroup_fields[field]
794 print "Added node group", nodegroup_id
796 def UpdateNodeGroups(self):
798 Make random changes to any node groups we may have added.
801 for nodegroup_id in self.nodegroup_ids:
803 (groupname, tagname, tagvalue) = random_nodegroup()
804 # cannot change tagname
805 nodegroup_fields = {'groupname':groupname,
807 self.api.UpdateNodeGroup(nodegroup_id, nodegroup_fields)
811 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
812 for field in nodegroup_fields:
813 assert nodegroup[field] == nodegroup_fields[field]
816 print "Updated node group", nodegroup_id
818 def DeleteNodeGroups(self):
820 Delete any random node groups we may have added.
823 for nodegroup_id in self.nodegroup_ids:
824 self.api.DeleteNodeGroup(nodegroup_id)
827 assert not self.api.GetNodeGroups([nodegroup_id])
830 print "Deleted node group", nodegroup_id
833 assert not self.api.GetNodeGroups(self.nodegroup_ids)
835 self.nodegroup_ids = []
837 def AddNodes(self, per_site = 2):
839 Add a number of random nodes to each site. Each node will also
840 be added to a random node group if AddNodeGroups() was
844 boot_states = self.api.GetBootStates()
846 raise Exception, "No boot states"
848 for site_id in self.site_ids:
849 for i in range(per_site):
851 node_fields = random_node(boot_states)
852 node_id = self.api.AddNode(site_id, node_fields)
854 # Should return a unique node_id
855 assert node_id not in self.node_ids
856 self.node_ids.append(node_id)
858 # Add to a random set of node groups
859 # nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
860 nodegroup_ids = random.sample(self.nodegroup_ids, len(self.nodegroup_ids))
861 for nodegroup_id in nodegroup_ids:
862 tagvalue = self.api.GetNodeGroups([nodegroup_id])[0]['tagvalue']
863 self.api.AddNodeTag( node_id, nodegroups_tagname, tagvalue )
867 node = self.api.GetNodes([node_id])[0]
868 for field in node_fields:
869 assert node[field] == node_fields[field]
872 print "Added node", node_id
874 def UpdateNodes(self):
876 Make random changes to any nodes we may have added.
879 boot_states = self.api.GetBootStates()
881 raise Exception, "No boot states"
883 for node_id in self.node_ids:
885 node_fields = random_node(boot_states)
886 self.api.UpdateNode(node_id, node_fields)
888 node = self.api.GetNodes([node_id])[0]
890 # Add to a random set of node groups
891 nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
892 for nodegroup_id in nodegroup_ids:
893 tagvalue = self.api.GetNodeGroups([nodegroup_id])[0]['tagvalue']
894 # with low lvl API, the tag is expected to already exist, so we need to *update* it
895 print 'DBG node_id',node_id,'nodegroups_tagname',nodegroups_tagname
896 node_tag = self.api.GetNodeTags( {'node_id':node_id, 'tagname':nodegroups_tagname } )[0]
897 self.api.UpdateNodeTag(node_tag['node_tag_id'],tagvalue)
898 print 'DBG node_tag_id',node_tag['node_tag_id']
903 node = self.api.GetNodes([node_id])[0]
904 for field in node_fields:
905 assert node[field] == node_fields[field]
906 assert set(nodegroup_ids) == set(node['nodegroup_ids'])
909 print "Updated node", node_id
910 print "Added node", node_id, "to node groups", nodegroup_ids
912 def DeleteNodes(self):
914 Delete any random nodes we may have added.
917 for node_id in self.node_ids:
918 # Remove from node groups
919 node = self.api.GetNodes([node_id])[0]
920 node_tag = GetNodeTags ( {'node_id': node_id, 'tagname': nodegroups_tagname } )[0]
921 self.api.UpdateNodeTag(node_tag['node_tag_id'],'')
924 node = self.api.GetNodes([node_id])[0]
925 assert not node['nodegroup_ids']
927 self.api.DeleteNode(node_id)
930 assert not self.api.GetNodes([node_id])
933 print "Deleted node", node_id
936 assert not self.api.GetNodes(self.node_ids)
940 def AddInterfaces(self, per_node = 1):
942 Add a number of random network interfaces to each node.
945 network_methods = self.api.GetNetworkMethods()
946 if not network_methods:
947 raise Exception, "No network methods"
949 network_types = self.api.GetNetworkTypes()
950 if not network_types:
951 raise Exception, "No network types"
953 for node_id in self.node_ids:
954 for i in range(per_node):
955 method = random.sample(network_methods, 1)[0]
956 type = random.sample(network_types, 1)[0]
959 interface_fields = random_interface(method, type)
960 interface_id = self.api.AddInterface(node_id, interface_fields)
962 # Should return a unique interface_id
963 assert interface_id not in self.interface_ids
964 self.interface_ids.append(interface_id)
968 interface = self.api.GetInterfaces([interface_id])[0]
969 for field in interface_fields:
970 assert interface[field] == interface_fields[field]
973 print "Added node network", interface_id, "to node", node_id
975 def UpdateInterfaces(self):
977 Make random changes to any network interfaces we may have added.
980 network_methods = self.api.GetNetworkMethods()
981 if not network_methods:
982 raise Exception, "No network methods"
984 network_types = self.api.GetNetworkTypes()
985 if not network_types:
986 raise Exception, "No network types"
988 for interface_id in self.interface_ids:
989 method = random.sample(network_methods, 1)[0]
990 type = random.sample(network_types, 1)[0]
993 interface_fields = random_interface(method, type)
994 self.api.UpdateInterface(interface_id, interface_fields)
998 interface = self.api.GetInterfaces([interface_id])[0]
999 for field in interface_fields:
1000 assert interface[field] == interface_fields[field]
1003 print "Updated node network", interface_id
1005 def DeleteInterfaces(self):
1007 Delete any random network interfaces we may have added.
1010 for interface_id in self.interface_ids:
1011 self.api.DeleteInterface(interface_id)
1014 assert not self.api.GetInterfaces([interface_id])
1017 print "Deleted node network", interface_id
1020 assert not self.api.GetInterfaces(self.interface_ids)
1022 self.interface_ids = []
1024 def AddPCUs(self, per_site = 1):
1026 Add a number of random PCUs to each site. Each node at the
1027 site will be added to a port on the PCU if AddNodes() was
1031 for site_id in self.site_ids:
1032 for i in range(per_site):
1034 pcu_fields = random_pcu()
1035 pcu_id = self.api.AddPCU(site_id, pcu_fields)
1037 # Should return a unique pcu_id
1038 assert pcu_id not in self.pcu_ids
1039 self.pcu_ids.append(pcu_id)
1041 # Add each node at this site to a different port on this PCU
1042 site = self.api.GetSites([site_id])[0]
1043 port = randint(1, 10)
1044 for node_id in site['node_ids']:
1045 self.api.AddNodeToPCU(node_id, pcu_id, port)
1050 pcu = self.api.GetPCUs([pcu_id])[0]
1051 for field in pcu_fields:
1052 assert pcu[field] == pcu_fields[field]
1055 print "Added PCU", pcu_id, "to site", site_id
1057 def UpdatePCUs(self):
1059 Make random changes to any PCUs we may have added.
1062 for pcu_id in self.pcu_ids:
1064 pcu_fields = random_pcu()
1065 self.api.UpdatePCU(pcu_id, pcu_fields)
1069 pcu = self.api.GetPCUs([pcu_id])[0]
1070 for field in pcu_fields:
1071 assert pcu[field] == pcu_fields[field]
1074 print "Updated PCU", pcu_id
1076 def DeletePCUs(self):
1078 Delete any random nodes we may have added.
1081 for pcu_id in self.pcu_ids:
1082 # Remove nodes from PCU
1083 pcu = self.api.GetPCUs([pcu_id])[0]
1084 for node_id in pcu['node_ids']:
1085 self.api.DeleteNodeFromPCU(node_id, pcu_id)
1088 pcu = self.api.GetPCUs([pcu_id])[0]
1089 assert not pcu['node_ids']
1091 self.api.DeletePCU(pcu_id)
1094 assert not self.api.GetPCUs([pcu_id])
1097 print "Deleted PCU", pcu_id
1100 assert not self.api.GetPCUs(self.pcu_ids)
1104 def AddConfFiles(self, n = 10):
1106 Add a number of random global configuration files.
1112 # Add a random configuration file
1113 conf_files.append(random_conf_file())
1116 # Add a nodegroup override file
1117 nodegroup_conf_file = conf_files[0].copy()
1118 nodegroup_conf_file['source'] = randpath(255)
1119 conf_files.append(nodegroup_conf_file)
1121 # Add a node override file
1122 node_conf_file = conf_files[0].copy()
1123 node_conf_file['source'] = randpath(255)
1124 conf_files.append(node_conf_file)
1126 for conf_file_fields in conf_files:
1127 conf_file_id = self.api.AddConfFile(conf_file_fields)
1129 # Should return a unique conf_file_id
1130 assert conf_file_id not in self.conf_file_ids
1131 self.conf_file_ids.append(conf_file_id)
1134 if conf_file_fields == nodegroup_conf_file and self.nodegroup_ids:
1135 nodegroup_id = random.sample(self.nodegroup_ids, 1)[0]
1136 self.api.AddConfFileToNodeGroup(conf_file_id, nodegroup_id)
1141 if conf_file_fields == node_conf_file and self.node_ids:
1142 node_id = random.sample(self.node_ids, 1)[0]
1143 self.api.AddConfFileToNode(conf_file_id, node_id)
1148 # Check configuration file
1149 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1150 for field in conf_file_fields:
1151 assert conf_file[field] == conf_file_fields[field]
1154 print "Added configuration file", conf_file_id,
1155 if nodegroup_id is not None:
1156 print "to node group", nodegroup_id,
1157 elif node_id is not None:
1158 print "to node", node_id,
1161 def UpdateConfFiles(self):
1163 Make random changes to any configuration files we may have added.
1166 for conf_file_id in self.conf_file_ids:
1167 # Update configuration file
1168 conf_file_fields = random_conf_file()
1169 # Do not update dest so that it remains an override if set
1170 if 'dest' in conf_file_fields:
1171 del conf_file_fields['dest']
1172 self.api.UpdateConfFile(conf_file_id, conf_file_fields)
1175 # Check configuration file
1176 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1177 for field in conf_file_fields:
1178 assert conf_file[field] == conf_file_fields[field]
1181 print "Updated configuration file", conf_file_id
1183 def DeleteConfFiles(self):
1185 Delete any random configuration files we may have added.
1188 for conf_file_id in self.conf_file_ids:
1189 self.api.DeleteConfFile(conf_file_id)
1192 assert not self.api.GetConfFiles([conf_file_id])
1195 print "Deleted configuration file", conf_file_id
1198 assert not self.api.GetConfFiles(self.conf_file_ids)
1200 self.conf_file_ids = []
1202 def AddSliceAttributeTypes(self, n = 10):
1204 Add a number of random slice attribute types.
1207 roles = self.api.GetRoles()
1209 raise Exception, "No roles"
1210 role_ids = [role['role_id'] for role in roles]
1213 attribute_type_fields = random_attribute_type(role_ids)
1214 attribute_type_id = self.api.AddSliceAttributeType(attribute_type_fields)
1216 # Should return a unique attribute_type_id
1217 assert attribute_type_id not in self.attribute_type_ids
1218 self.attribute_type_ids.append(attribute_type_id)
1221 # Check slice attribute type
1222 attribute_type = self.api.GetSliceAttributeTypes([attribute_type_id])[0]
1223 for field in attribute_type_fields:
1224 assert attribute_type[field] == attribute_type_fields[field]
1227 print "Added slice attribute type", attribute_type_id
1229 def UpdateSliceAttributeTypes(self):
1231 Make random changes to any slice attribute types we may have added.
1234 roles = self.api.GetRoles()
1236 raise Exception, "No roles"
1237 role_ids = [role['role_id'] for role in roles]
1239 for attribute_type_id in self.attribute_type_ids:
1240 # Update slice attribute type
1241 attribute_type_fields = random_attribute_type(role_ids)
1242 self.api.UpdateSliceAttributeType(attribute_type_id, attribute_type_fields)
1245 # Check slice attribute type
1246 attribute_type = self.api.GetSliceAttributeTypes([attribute_type_id])[0]
1247 for field in attribute_type_fields:
1248 assert attribute_type[field] == attribute_type_fields[field]
1251 print "Updated slice attribute type", attribute_type_id
1253 def DeleteSliceAttributeTypes(self):
1255 Delete any random slice attribute types we may have added.
1258 for attribute_type_id in self.attribute_type_ids:
1259 self.api.DeleteSliceAttributeType(attribute_type_id)
1262 assert not self.api.GetSliceAttributeTypes([attribute_type_id])
1265 print "Deleted slice attribute type", attribute_type_id
1268 assert not self.api.GetSliceAttributeTypes(self.attribute_type_ids)
1270 self.attribute_type_ids = []
1272 def AddSlices(self, per_site = 10):
1274 Add a number of random slices per site.
1277 for site in self.api.GetSites(self.site_ids):
1278 for i in range(min(per_site, site['max_slices'])):
1280 slice_fields = random_slice(site['login_base'])
1281 slice_id = self.api.AddSlice(slice_fields)
1283 # Should return a unique slice_id
1284 assert slice_id not in self.slice_ids
1285 self.slice_ids.append(slice_id)
1287 # Add slice to a random set of nodes
1288 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1290 self.api.AddSliceToNodes(slice_id, node_ids)
1292 # Add random set of site users to slice
1293 person_ids = random.sample(site['person_ids'], randint(0, len(site['person_ids'])))
1294 for person_id in person_ids:
1295 self.api.AddPersonToSlice(person_id, slice_id)
1299 slice = self.api.GetSlices([slice_id])[0]
1300 for field in slice_fields:
1301 assert slice[field] == slice_fields[field]
1303 assert set(node_ids) == set(slice['node_ids'])
1304 assert set(person_ids) == set(slice['person_ids'])
1307 print "Added slice", slice_id, "to site", site['site_id'],
1309 print "and nodes", node_ids,
1312 print "Added users", site['person_ids'], "to slice", slice_id
1314 def UpdateSlices(self):
1316 Make random changes to any slices we may have added.
1319 for slice_id in self.slice_ids:
1321 slice_fields = random_slice("unused")
1322 # Cannot change slice name
1323 if 'name' in slice_fields:
1324 del slice_fields['name']
1325 self.api.UpdateSlice(slice_id, slice_fields)
1327 slice = self.api.GetSlices([slice_id])[0]
1329 # Add slice to a random set of nodes
1330 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1331 self.api.AddSliceToNodes(slice_id, list(set(node_ids) - set(slice['node_ids'])))
1332 self.api.DeleteSliceFromNodes(slice_id, list(set(slice['node_ids']) - set(node_ids)))
1334 # Add random set of users to slice
1335 person_ids = random.sample(self.person_ids, randint(0, len(self.person_ids)))
1336 for person_id in (set(person_ids) - set(slice['person_ids'])):
1337 self.api.AddPersonToSlice(person_id, slice_id)
1338 for person_id in (set(slice['person_ids']) - set(person_ids)):
1339 self.api.DeletePersonFromSlice(person_id, slice_id)
1342 slice = self.api.GetSlices([slice_id])[0]
1343 for field in slice_fields:
1344 assert slice[field] == slice_fields[field]
1345 assert set(node_ids) == set(slice['node_ids'])
1346 assert set(person_ids) == set(slice['person_ids'])
1349 print "Updated slice", slice_id
1350 print "Added nodes", node_ids, "to slice", slice_id
1351 print "Added persons", person_ids, "to slice", slice_id
1353 def DeleteSlices(self):
1355 Delete any random slices we may have added.
1358 for slice_id in self.slice_ids:
1359 self.api.DeleteSlice(slice_id)
1362 assert not self.api.GetSlices([slice_id])
1365 print "Deleted slice", slice_id
1368 assert not self.api.GetSlices(self.slice_ids)
1372 def AddSliceAttributes(self, per_slice = 2):
1374 Add a number of random slices per site.
1377 if not self.attribute_type_ids:
1380 for slice_id in self.slice_ids:
1381 slice = self.api.GetSlices([slice_id])[0]
1383 for i in range(per_slice):
1384 # Set a random slice/sliver attribute
1385 for attribute_type_id in random.sample(self.attribute_type_ids, 1):
1386 value = randstr(16, letters + '_' + digits)
1387 # Make it a sliver attribute with 50% probability
1388 if slice['node_ids']:
1389 node_id = random.sample(slice['node_ids'] + [None] * len(slice['node_ids']), 1)[0]
1393 # Add slice attribute
1395 slice_attribute_id = self.api.AddSliceAttribute(slice_id, attribute_type_id, value)
1397 slice_attribute_id = self.api.AddSliceAttribute(slice_id, attribute_type_id, value, node_id)
1399 # Should return a unique slice_attribute_id
1400 assert slice_attribute_id not in self.slice_attribute_ids
1401 self.slice_attribute_ids.append(slice_attribute_id)
1404 # Check slice attribute
1405 slice_attribute = self.api.GetSliceAttributes([slice_attribute_id])[0]
1406 for field in 'attribute_type_id', 'slice_id', 'node_id', 'slice_attribute_id', 'value':
1407 assert slice_attribute[field] == locals()[field]
1410 print "Added slice attribute", slice_attribute_id, "of type", attribute_type_id,
1411 if node_id is not None:
1412 print "to node", node_id,
1415 def UpdateSliceAttributes(self):
1417 Make random changes to any slice attributes we may have added.
1420 for slice_attribute_id in self.slice_attribute_ids:
1421 # Update slice attribute
1422 value = randstr(16, letters + '_' + digits)
1423 self.api.UpdateSliceAttribute(slice_attribute_id, value)
1425 # Check slice attribute again
1426 slice_attribute = self.api.GetSliceAttributes([slice_attribute_id])[0]
1427 assert slice_attribute['value'] == value
1430 print "Updated slice attribute", slice_attribute_id
1432 def DeleteSliceAttributes(self):
1434 Delete any random slice attributes we may have added.
1437 for slice_attribute_id in self.slice_attribute_ids:
1438 self.api.DeleteSliceAttribute(slice_attribute_id)
1441 assert not self.api.GetSliceAttributes([slice_attribute_id])
1444 print "Deleted slice attribute", slice_attribute_id
1447 assert not self.api.GetSliceAttributes(self.slice_attribute_ids)
1449 self.slice_attribute_ids = []
1452 parser = OptionParser()
1453 parser.add_option("-c", "--check", action = "store_true", default = False,
1454 help = "Check most actions (default: %default)")
1455 parser.add_option("-q", "--quiet", action = "store_true", default = False,
1456 help = "Be quiet (default: %default)")
1457 parser.add_option("-t", "--tiny", action = "store_true", default = False,
1458 help = "Run a tiny test (default: %default)")
1459 (options, args) = parser.parse_args()
1461 test = Test(api = Shell(),
1462 check = options.check,
1463 verbose = not options.quiet)
1468 params = Test.default
1472 if __name__ == "__main__":