renaming SliceAttribute into SliceTag and InterfaceSetting into InterfaceTag
[tests.git] / system / plcsh-stress-test.py
1 #!/usr/bin/env plcsh
2 #
3 # Test script utility class
4 #
5 # Mark Huang <mlhuang@cs.princeton.edu>
6 # Copyright (C) 2006 The Trustees of Princeton University
7 #
8 # $Id$
9 #
10
11 from pprint import pprint
12 from string import letters, digits, punctuation
13 from traceback import print_exc
14 from optparse import OptionParser
15 import socket
16 import base64
17 import struct
18 import os
19 import xmlrpclib
20
21 from PLC.Shell import Shell
22
23 from random import Random
24 random = Random()
25
26 def randfloat(min = 0.0, max = 1.0):
27     return float(min) + (random.random() * (float(max) - float(min)))
28
29 def randint(min = 0, max = 1):
30     return int(randfloat(min, max + 1))
31
32 # See "2.2 Characters" in the XML specification:
33 #
34 # #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
35 # avoiding
36 # [#x7F-#x84], [#x86-#x9F], [#xFDD0-#xFDDF]
37 #
38
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
42 # still the case.
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))
53
54 def randstr(length, pool = valid_xml_chars, encoding = "utf-8"):
55     sample = random.sample(pool, min(length, len(pool)))
56     while True:
57         s = u''.join(sample)
58         bytes = len(s.encode(encoding))
59         if bytes > length:
60             sample.pop()
61         elif bytes < length:
62             sample += random.sample(pool, min(length - bytes, len(pool)))
63             random.shuffle(sample)
64         else:
65             break
66     return s
67
68 def randhostname():
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)
77     return hostname
78
79 def randpath(length):
80     parts = []
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]
84
85 def randemail():
86     return (randstr(100, letters + digits) + "@" + randhostname()).lower()
87
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"))),
93                      randemail()])
94
95 def random_site():
96     return {
97         'name': randstr(254),
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,
102         }
103             
104 def random_address_type():
105     return {
106         'name': randstr(20),
107         'description': randstr(254),
108         }
109
110 def random_address():
111     return {
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),
119         }
120
121 def random_person():
122     return {
123         'first_name': randstr(128),
124         'last_name': randstr(128),
125         'email': randemail(),
126         'bio': randstr(254),
127         # Accounts are disabled by default
128         'enabled': False,
129         'password': randstr(254),
130         }
131
132 def random_key(key_types):
133     return {
134         'key_type': random.sample(key_types, 1)[0],
135         'key': randkey()
136         }
137
138 def random_tag_type (role_ids):
139     return  {'tagname': randstr(12),
140              'category':randstr(8),
141              'min_role_id': random.sample(role_ids, 1)[0],
142              'description' : randstr(128),
143              }
144
145 def random_nodegroup():
146     return {'groupname' : randstr(50) }
147
148 def random_node(boot_states):
149     return {
150         'hostname': randhostname(),
151         'boot_state': random.sample(boot_states, 1)[0],
152         'model': randstr(255),
153         'version': randstr(64),
154         }
155
156 def random_interface(method, type):
157     interface_fields = {
158         'method': method,
159         'type': type,
160         'bwlimit': randint(500000, 10000000),
161         }
162
163     if method != 'dhcp':
164         ip = randint(0, 0xffffffff)
165         netmask = (0xffffffff << randint(2, 31)) & 0xffffffff
166         network = ip & netmask
167         broadcast = ((ip & netmask) | ~netmask) & 0xffffffff
168         gateway = randint(network + 1, broadcast - 1)
169         dns1 = randint(0, 0xffffffff)
170
171         for field in 'ip', 'netmask', 'network', 'broadcast', 'gateway', 'dns1':
172             interface_fields[field] = socket.inet_ntoa(struct.pack('>L', locals()[field]))
173
174     return interface_fields
175
176 def random_ilink ():
177     return randstr (12)
178
179 def random_pcu():
180     return {
181         'hostname': randhostname(),
182         'ip': socket.inet_ntoa(struct.pack('>L', randint(0, 0xffffffff))),
183         'protocol': randstr(16),
184         'username': randstr(254),
185         'password': randstr(254),
186         'notes': randstr(254),
187         'model': randstr(32),
188         }
189
190 def random_conf_file():
191     return {
192         'enabled': bool(randint()),
193         'source': randpath(255),
194         'dest': randpath(255),
195         'file_permissions': "%#o" % randint(0, 512),
196         'file_owner': randstr(32, letters + '_' + digits),
197         'file_group': randstr(32, letters + '_' + digits),
198         'preinstall_cmd': randpath(100),
199         'postinstall_cmd': randpath(100),
200         'error_cmd': randpath(100),
201         'ignore_cmd_errors': bool(randint()),
202         'always_update': bool(randint()),
203         }
204
205 def random_slice(login_base):
206     return {
207         'name': login_base + "_" + randstr(11, letters).lower(),
208         'url': "http://" + randhostname() + "/",
209         'description': randstr(2048),
210         }
211
212 class Test:
213     tiny = {
214         'sites': 1,
215         'address_types': 1,
216         'addresses_per_site': 1,
217         'persons_per_site': 1,
218         'keys_per_person': 1,
219         'slice_tags': 1,
220         'nodegroups': 1,
221         'nodes_per_site': 1,
222         'interfaces_per_node': 1,
223         'ilinks':1,
224         'pcus_per_site': 1,
225         'conf_files': 1,
226         'slices_per_site': 1,
227         'attributes_per_slice': 1,
228         }
229
230     default = {
231         'sites': 10,
232         'address_types': 2,
233         'addresses_per_site': 2,
234         'persons_per_site': 4,
235         'keys_per_person': 2,
236         'slice_tags': 10,
237         'nodegroups': 10,
238         'nodes_per_site': 2,
239         'interfaces_per_node': 1,
240         'ilinks': 20,
241         'pcus_per_site': 1,
242         'conf_files': 10,
243         'slices_per_site': 4,
244         'attributes_per_slice': 2,
245         }
246
247     def __init__(self, api, check = True, verbose = True, preserve = False):
248         self.api = api
249         self.check = check
250         self.verbose = verbose
251         self.preserve = preserve
252         
253         self.site_ids = []
254         self.address_type_ids = []
255         self.address_ids = []
256         self.person_ids = []
257         self.key_ids = []
258         self.slice_type_ids = []
259         self.nodegroup_type_ids = []
260         self.ilink_type_ids = []
261         self.nodegroup_ids = []
262         self.node_ids = []
263         self.interface_ids = []
264         self.ilink_ids = []
265         self.pcu_ids = []
266         self.conf_file_ids = []
267         self.slice_ids = []
268         self.slice_tag_ids = []
269
270     def Run(self, **kwds):
271         """
272         Run a complete database and API consistency test. Populates
273         the database with a set of random entities, updates them, then
274         deletes them. Examples:
275
276         test.Run() # Defaults
277         test.Run(**Test.default) # Defaults
278         test.Run(**Test.tiny) # Tiny set
279         test.Run(sites = 123, slices_per_site = 4) # Defaults with overrides
280         """
281
282         self.Add(**kwds)
283         self.Update()
284         if self.preserve:
285             print 'Preserving - delete skipped'
286         else:
287             self.Delete()
288
289     def Add(self, **kwds):
290         """
291         Populate the database with a set of random entities. Examples:
292
293         test.populate() # Defaults
294         test.populate(Test.tiny) # Tiny set
295         test.populate(sites = 123, slices_per_site = 4) # Defaults with overrides
296         """
297
298         params = self.default.copy()
299         params.update(kwds)
300
301         self.AddSites(params['sites'])
302         self.AddAddressTypes(params['address_types'])
303         self.AddAddresses(params['addresses_per_site'])
304         self.AddPersons(params['persons_per_site'])
305         self.AddKeys(params['keys_per_person'])
306         self.AddTagTypes(params['slice_tags'],params['nodegroups'],params['ilinks'])
307         self.AddNodeGroups(params['nodegroups'])
308         self.AddNodes(params['nodes_per_site'])
309         self.AddInterfaces(params['interfaces_per_node'])
310         self.AddIlinks (params['ilinks'])
311         self.AddPCUs(params['pcus_per_site'])
312         self.AddConfFiles(params['conf_files'])
313         self.AddSlices(params['slices_per_site'])
314         self.AddSliceTags(params['attributes_per_slice'])
315
316     def Update(self):
317         self.UpdateSites()
318         self.UpdateAddressTypes()
319         self.UpdateAddresses()
320         self.UpdatePersons()
321         self.UpdateKeys()
322         self.UpdateTagTypes()
323         self.UpdateNodeGroups()
324         self.UpdateNodes()
325         self.UpdateInterfaces()
326         self.UpdateIlinks()
327         self.UpdatePCUs()
328         self.UpdateConfFiles()
329         self.UpdateSlices()
330         self.UpdateSliceTags()
331
332     def Delete(self):
333         self.DeleteSliceTags()
334         self.DeleteSlices()
335         self.DeleteKeys()
336         self.DeleteConfFiles()
337         self.DeletePCUs()
338         self.DeleteIlinks()
339         self.DeleteInterfaces()
340         self.DeleteNodes()
341         self.DeletePersons()
342         self.DeleteNodeGroups()
343         self.DeleteTagTypes()
344         self.DeleteAddresses()
345         self.DeleteAddressTypes()
346         self.DeleteSites()
347
348     def AddSites(self, n = 10):
349         """
350         Add a number of random sites.
351         """
352
353         for i in range(n):
354             # Add site
355             site_fields = random_site()
356             site_id = self.api.AddSite(site_fields)
357
358             # Should return a unique site_id
359             assert site_id not in self.site_ids
360             self.site_ids.append(site_id)
361
362             # Enable slice creation
363             site_fields['max_slices'] = randint(1, 10)
364             self.api.UpdateSite(site_id, site_fields)
365
366             if self.check:
367                 # Check site
368                 site = self.api.GetSites([site_id])[0]
369                 for field in site_fields:
370                     assert site[field] == site_fields[field]
371
372             if self.verbose:
373                 print "Added site", site_id
374
375     def UpdateSites(self):
376         """
377         Make random changes to any sites we may have added.
378         """
379
380         for site_id in self.site_ids:
381             # Update site
382             site_fields = random_site()
383             # Do not change login_base
384             if 'login_base' in site_fields:
385                 del site_fields['login_base']
386             self.api.UpdateSite(site_id, site_fields)
387
388             if self.check:
389                 # Check site
390                 site = self.api.GetSites([site_id])[0]
391                 for field in site_fields:
392                     assert site[field] == site_fields[field]
393
394             if self.verbose:
395                 print "Updated site", site_id
396
397     def DeleteSites(self):
398         """
399         Delete any random sites we may have added.
400         """
401
402         for site_id in self.site_ids:
403             self.api.DeleteSite(site_id)
404
405             if self.check:
406                 assert not self.api.GetSites([site_id])
407
408             if self.verbose:
409                 print "Deleted site", site_id
410
411         if self.check:
412             assert not self.api.GetSites(self.site_ids)
413
414         self.site_ids = []
415
416     def AddAddressTypes(self, n = 2):
417         """
418         Add a number of random address types.
419         """
420
421         for i in range(n):
422             address_type_fields = random_address_type()
423             address_type_id = self.api.AddAddressType(address_type_fields)
424
425             # Should return a unique address_type_id
426             assert address_type_id not in self.address_type_ids
427             self.address_type_ids.append(address_type_id)
428
429             if self.check:
430                 # Check address type
431                 address_type = self.api.GetAddressTypes([address_type_id])[0]
432                 for field in address_type_fields:
433                     assert address_type[field] == address_type_fields[field]
434
435             if self.verbose:
436                 print "Added address type", address_type_id
437
438     def UpdateAddressTypes(self):
439         """
440         Make random changes to any address types we may have added.
441         """
442
443         for address_type_id in self.address_type_ids:
444             # Update address_type
445             address_type_fields = random_address_type()
446             self.api.UpdateAddressType(address_type_id, address_type_fields)
447
448             if self.check:
449                 # Check address type
450                 address_type = self.api.GetAddressTypes([address_type_id])[0]
451                 for field in address_type_fields:
452                     assert address_type[field] == address_type_fields[field]
453
454             if self.verbose:
455                 print "Updated address_type", address_type_id
456
457     def DeleteAddressTypes(self):
458         """
459         Delete any random address types we may have added.
460         """
461
462         for address_type_id in self.address_type_ids:
463             self.api.DeleteAddressType(address_type_id)
464
465             if self.check:
466                 assert not self.api.GetAddressTypes([address_type_id])
467
468             if self.verbose:
469                 print "Deleted address type", address_type_id
470
471         if self.check:
472             assert not self.api.GetAddressTypes(self.address_type_ids)
473
474         self.address_type_ids = []
475
476     def AddAddresses(self, per_site = 2):
477         """
478         Add a number of random addresses to each site.
479         """
480
481         for site_id in self.site_ids:
482             for i in range(per_site):
483                 address_fields = random_address()
484                 address_id = self.api.AddSiteAddress(site_id, address_fields)
485
486                 # Should return a unique address_id
487                 assert address_id not in self.address_ids
488                 self.address_ids.append(address_id)
489
490                 # Add random address type
491                 if self.address_type_ids:
492                     for address_type_id in random.sample(self.address_type_ids, 1):
493                         self.api.AddAddressTypeToAddress(address_type_id, address_id)
494
495                 if self.check:
496                     # Check address
497                     address = self.api.GetAddresses([address_id])[0]
498                     for field in address_fields:
499                         assert address[field] == address_fields[field]
500
501                 if self.verbose:
502                     print "Added address", address_id, "to site", site_id
503
504     def UpdateAddresses(self):
505         """
506         Make random changes to any addresses we may have added.
507         """
508
509         for address_id in self.address_ids:
510             # Update address
511             address_fields = random_address()
512             self.api.UpdateAddress(address_id, address_fields)
513
514             if self.check:
515                 # Check address
516                 address = self.api.GetAddresses([address_id])[0]
517                 for field in address_fields:
518                     assert address[field] == address_fields[field]
519
520             if self.verbose:
521                 print "Updated address", address_id
522
523     def DeleteAddresses(self):
524         """
525         Delete any random addresses we may have added.
526         """
527
528         for address_id in self.address_ids:
529             # Remove address types
530             address = self.api.GetAddresses([address_id])[0]
531             for address_type_id in address['address_type_ids']:
532                 self.api.DeleteAddressTypeFromAddress(address_type_id, address_id)
533
534             if self.check:
535                 address = self.api.GetAddresses([address_id])[0]
536                 assert not address['address_type_ids']
537
538             self.api.DeleteAddress(address_id)
539
540             if self.check:
541                 assert not self.api.GetAddresses([address_id])
542
543             if self.verbose:
544                 print "Deleted address", address_id
545
546         if self.check:
547             assert not self.api.GetAddresses(self.address_ids)
548
549         self.address_ids = []
550
551     def AddPersons(self, per_site = 10):
552         """
553         Add a number of random users to each site.
554         """
555
556         for site_id in self.site_ids:
557             for i in range(per_site):
558                 # Add user
559                 person_fields = random_person()
560                 person_id = self.api.AddPerson(person_fields)
561
562                 # Should return a unique person_id
563                 assert person_id not in self.person_ids
564                 self.person_ids.append(person_id)
565
566                 if self.check:
567                     # Check user
568                     person = self.api.GetPersons([person_id])[0]
569                     for field in person_fields:
570                         if field != 'password':
571                             assert person[field] == person_fields[field]
572
573                 auth = {'AuthMethod': "password",
574                         'Username': person_fields['email'],
575                         'AuthString': person_fields['password']}
576
577                 if self.check:
578                     # Check that user is disabled
579                     try:
580                         assert not self.api.AuthCheck(auth)
581                     except:
582                         pass
583
584                 # Add random set of roles
585                 role_ids = random.sample([20, 30, 40], randint(1, 3))
586                 for role_id in role_ids:
587                     self.api.AddRoleToPerson(role_id, person_id)
588
589                 if self.check:
590                     person = self.api.GetPersons([person_id])[0]
591                     assert set(role_ids) == set(person['role_ids'])
592
593                 # Enable user
594                 self.api.UpdatePerson(person_id, {'enabled': True})
595
596                 if self.check:
597                     # Check that user is enabled
598                     assert self.api.AuthCheck(auth)
599
600                 # Associate user with site
601                 self.api.AddPersonToSite(person_id, site_id)
602                 self.api.SetPersonPrimarySite(person_id, site_id)
603
604                 if self.check:
605                     person = self.api.GetPersons([person_id])[0]
606                     assert person['site_ids'][0] == site_id
607
608                 if self.verbose:
609                     print "Added user", person_id, "to site", site_id
610
611     def UpdatePersons(self):
612         """
613         Make random changes to any users we may have added.
614         """
615
616         for person_id in self.person_ids:
617             # Update user
618             person_fields = random_person()
619             # Keep them enabled
620             person_fields['enabled'] = True
621             self.api.UpdatePerson(person_id, person_fields)
622
623             if self.check:
624                 # Check user
625                 person = self.api.GetPersons([person_id])[0]
626                 for field in person_fields:
627                     if field != 'password':
628                         assert person[field] == person_fields[field]
629
630             if self.verbose:
631                 print "Updated person", person_id
632
633             person = self.api.GetPersons([person_id])[0]
634
635             # Associate user with a random set of sites
636             site_ids = random.sample(self.site_ids, randint(0, len(self.site_ids)))
637             for site_id in (set(site_ids) - set(person['site_ids'])):
638                 self.api.AddPersonToSite(person_id, site_id)
639             for site_id in (set(person['site_ids']) - set(site_ids)):
640                 self.api.DeletePersonFromSite(person_id, site_id)
641
642             if site_ids:
643                 self.api.SetPersonPrimarySite(person_id, site_ids[0])
644
645             if self.check:
646                 person = self.api.GetPersons([person_id])[0]
647                 assert set(site_ids) == set(person['site_ids'])
648
649             if self.verbose:
650                 print "Updated person", person_id, "to sites", site_ids
651
652     def DeletePersons(self):
653         """
654         Delete any random users we may have added.
655         """
656
657         for person_id in self.person_ids:
658             # Remove from site
659             person = self.api.GetPersons([person_id])[0]
660             for site_id in person['site_ids']:
661                 self.api.DeletePersonFromSite(person_id, site_id)
662
663             if self.check:
664                 person = self.api.GetPersons([person_id])[0]
665                 assert not person['site_ids']
666
667             # Revoke roles
668             for role_id in person['role_ids']:
669                 self.api.DeleteRoleFromPerson(role_id, person_id)
670
671             if self.check:
672                 person = self.api.GetPersons([person_id])[0]
673                 assert not person['role_ids']
674
675             # Disable account
676             self.api.UpdatePerson(person_id, {'enabled': False})
677
678             if self.check:
679                 person = self.api.GetPersons([person_id])[0]
680                 assert not person['enabled']
681
682             # Delete account
683             self.api.DeletePerson(person_id)
684
685             if self.check:
686                 assert not self.api.GetPersons([person_id])                         
687
688             if self.verbose:
689                 print "Deleted user", person_id
690
691         if self.check:
692             assert not self.api.GetPersons(self.person_ids)
693
694         self.person_ids = []
695
696     def AddKeys(self, per_person = 2):
697         """
698         Add a number of random keys to each user.
699         """
700
701         key_types = self.api.GetKeyTypes()
702         if not key_types:
703             raise Exception, "No key types"
704
705         for person_id in self.person_ids:
706             for i in range(per_person):
707                 # Add key
708                 key_fields = random_key(key_types)
709                 key_id = self.api.AddPersonKey(person_id, key_fields)
710
711                 # Should return a unique key_id
712                 assert key_id not in self.key_ids
713                 self.key_ids.append(key_id)
714
715                 if self.check:
716                     # Check key
717                     key = self.api.GetKeys([key_id])[0]
718                     for field in key_fields:
719                         assert key[field] == key_fields[field]
720
721                     # Add and immediately blacklist a key
722                     key_fields = random_key(key_types)
723                     key_id = self.api.AddPersonKey(person_id, key_fields)
724
725                     self.api.BlacklistKey(key_id)
726
727                     # Is effectively deleted
728                     assert not self.api.GetKeys([key_id])
729
730                     # Cannot be added again
731                     try:
732                         key_id = self.api.AddPersonKey(person_id, key_fields)
733                         assert False
734                     except Exception, e:
735                         pass
736
737                 if self.verbose:
738                     print "Added key", key_id, "to user", person_id
739
740     def UpdateKeys(self):
741         """
742         Make random changes to any keys we may have added.
743         """
744
745         key_types = self.api.GetKeyTypes()
746         if not key_types:
747             raise Exception, "No key types"
748
749         for key_id in self.key_ids:
750             # Update key
751             key_fields = random_key(key_types)
752             self.api.UpdateKey(key_id, key_fields)
753
754             if self.check:
755                 # Check key
756                 key = self.api.GetKeys([key_id])[0]
757                 for field in key_fields:
758                     assert key[field] == key_fields[field]
759
760             if self.verbose:
761                 print "Updated key", key_id
762
763     def DeleteKeys(self):
764         """
765         Delete any random keys we may have added.
766         """
767
768         for key_id in self.key_ids:
769             self.api.DeleteKey(key_id)
770
771             if self.check:
772                 assert not self.api.GetKeys([key_id])
773
774             if self.verbose:
775                 print "Deleted key", key_id
776
777         if self.check:
778             assert not self.api.GetKeys(self.key_ids)
779
780         self.key_ids = []
781
782     def AddNodeGroups(self, n = 10):
783         """
784         Add a number of random node groups.
785         """
786
787         for i in range(n):
788             # locate tag type
789             tag_type_id = self.nodegroup_type_ids[i]
790             tagname=self.api.GetTagTypes([tag_type_id])[0]['tagname']
791             
792             # Add node group
793             groupname = random_nodegroup() ['groupname']
794             tagvalue = 'yes'
795             nodegroup_id = self.api.AddNodeGroup(groupname, tagname, tagvalue)
796
797             # Should return a unique nodegroup_id
798             assert nodegroup_id not in self.nodegroup_ids
799             self.nodegroup_ids.append(nodegroup_id)
800
801             if self.check:
802                 # Check node group
803                 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
804                 assert nodegroup['groupname'] == groupname
805                 assert nodegroup['tagname'] == tagname
806                 assert nodegroup['tagvalue'] == tagvalue
807
808             if self.verbose:
809                 print "Added node group", nodegroup_id
810
811     def UpdateNodeGroups(self):
812         """
813         Make random changes to any node groups we may have added.
814         """
815
816         for nodegroup_id in self.nodegroup_ids:
817             # Update nodegroup
818             groupname = random_nodegroup()['groupname']
819             # cannot change tagname
820             nodegroup_fields = { 'groupname':groupname }
821             self.api.UpdateNodeGroup(nodegroup_id, nodegroup_fields)
822
823             if self.check:
824                 # Check nodegroup
825                 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
826                 for field in nodegroup_fields:
827                     assert nodegroup[field] == nodegroup_fields[field]
828
829             if self.verbose:
830                 print "Updated node group", nodegroup_id
831
832     def DeleteNodeGroups(self):
833         """
834         Delete any random node groups we may have added.
835         """
836
837         for nodegroup_id in self.nodegroup_ids:
838             self.api.DeleteNodeGroup(nodegroup_id)
839
840             if self.check:
841                 assert not self.api.GetNodeGroups([nodegroup_id])
842
843             if self.verbose:
844                 print "Deleted node group", nodegroup_id
845
846         if self.check:
847             assert not self.api.GetNodeGroups(self.nodegroup_ids)
848
849         self.nodegroup_ids = []
850
851     def AddNodes(self, per_site = 2):
852         """
853         Add a number of random nodes to each site. Each node will also
854         be added to a random node group if AddNodeGroups() was
855         previously run.
856         """
857         
858         boot_states = self.api.GetBootStates()
859         if not boot_states:
860             raise Exception, "No boot states"
861
862         for site_id in self.site_ids:
863             for i in range(per_site):
864                 # Add node
865                 node_fields = random_node(boot_states)
866                 node_id = self.api.AddNode(site_id, node_fields)
867
868                 # Should return a unique node_id
869                 assert node_id not in self.node_ids
870                 self.node_ids.append(node_id)
871
872                 # Add to a random set of node groups
873                 nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
874                 for nodegroup_id in nodegroup_ids:
875                     tagname = self.api.GetNodeGroups([nodegroup_id])[0]['tagname']
876                     self.api.AddNodeTag( node_id, tagname, 'yes' )
877
878                 if self.check:
879                     # Check node
880                     node = self.api.GetNodes([node_id])[0]
881                     for field in node_fields:
882                         assert node[field] == node_fields[field]
883
884                 if self.verbose:
885                     print "Added node", node_id
886
887     def UpdateNodes(self):
888         """
889         Make random changes to any nodes we may have added.
890         """
891
892         boot_states = self.api.GetBootStates()
893         if not boot_states:
894             raise Exception, "No boot states"
895
896         for node_id in self.node_ids:
897             # Update node
898             node_fields = random_node(boot_states)
899             self.api.UpdateNode(node_id, node_fields)
900
901             node = self.api.GetNodes([node_id])[0]
902
903             # Add to a random set of node groups
904             nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
905             for nodegroup_id in (set(nodegroup_ids) - set(node['nodegroup_ids'])):
906                 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
907                 tagname = nodegroup['tagname']
908                 node_tags = self.api.GetNodeTags({'node_id':node_id,'tagname':tagname})
909                 if not node_tags:
910                     self.api.AddNodeTag(node_id,tagname,'yes')
911                 else:
912                     node_tag=node_tags[0]
913                     self.api.UpdateNodeTag(node_tag['node_tag_id'],'yes')
914             for nodegroup_id in (set(node['nodegroup_ids']) - set(nodegroup_ids)):
915                 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
916                 tagname = nodegroup['tagname']
917                 node_tags = self.api.GetNodeTags({'node_id':node_id,'tagname':tagname})
918                 if not node_tags:
919                     self.api.AddNodeTag(node_id,tagname,'no')
920                 else:
921                     node_tag=node_tags[0]
922                     self.api.UpdateNodeTag(node_tag['node_tag_id'],'no')
923
924             if self.check:
925                 # Check node
926                 node = self.api.GetNodes([node_id])[0]
927                 for field in node_fields:
928                     assert node[field] == node_fields[field]
929                 assert set(nodegroup_ids) == set(node['nodegroup_ids'])
930
931             if self.verbose:
932                 print "Updated node", node_id
933
934     def DeleteNodes(self):
935         """
936         Delete any random nodes we may have added.
937         """
938
939         for node_id in self.node_ids:
940             # Remove from node groups
941             node = self.api.GetNodes([node_id])[0]
942             for node_tag in GetNodeTags ( {'node_id': node_id} ):
943                 self.api.UpdateNodeTag(node_tag['node_tag_id'],'')
944
945             if self.check:
946                 node = self.api.GetNodes([node_id])[0]
947                 assert not node['nodegroup_ids']
948
949             self.api.DeleteNode(node_id)
950
951             if self.check:
952                 assert not self.api.GetNodes([node_id])
953
954             if self.verbose:
955                 print "Deleted node", node_id
956
957         if self.check:
958             assert not self.api.GetNodes(self.node_ids)
959
960         self.node_ids = []
961
962     def AddInterfaces(self, per_node = 1):
963         """
964         Add a number of random network interfaces to each node.
965         """
966
967         network_methods = self.api.GetNetworkMethods()
968         if not network_methods:
969             raise Exception, "No network methods"
970         
971         network_types = self.api.GetNetworkTypes()
972         if not network_types:
973             raise Exception, "No network types"
974
975         for node_id in self.node_ids:
976             for i in range(per_node):
977                 method = random.sample(network_methods, 1)[0]
978                 type = random.sample(network_types, 1)[0]
979
980                 # Add interface
981                 interface_fields = random_interface(method, type)
982                 interface_id = self.api.AddInterface(node_id, interface_fields)
983
984                 # Should return a unique interface_id
985                 assert interface_id not in self.interface_ids
986                 self.interface_ids.append(interface_id)
987
988                 if self.check:
989                     # Check interface
990                     interface = self.api.GetInterfaces([interface_id])[0]
991                     for field in interface_fields:
992                         assert interface[field] == interface_fields[field]
993
994                 if self.verbose:
995                     print "Added interface", interface_id, "to node", node_id
996
997     def UpdateInterfaces(self):
998         """
999         Make random changes to any network interfaces we may have added.
1000         """
1001
1002         network_methods = self.api.GetNetworkMethods()
1003         if not network_methods:
1004             raise Exception, "No network methods"
1005         
1006         network_types = self.api.GetNetworkTypes()
1007         if not network_types:
1008             raise Exception, "No network types"
1009
1010         for interface_id in self.interface_ids:
1011             method = random.sample(network_methods, 1)[0]
1012             type = random.sample(network_types, 1)[0]
1013
1014             # Update interface
1015             interface_fields = random_interface(method, type)
1016             self.api.UpdateInterface(interface_id, interface_fields)
1017
1018             if self.check:
1019                 # Check interface
1020                 interface = self.api.GetInterfaces([interface_id])[0]
1021                 for field in interface_fields:
1022                     assert interface[field] == interface_fields[field]
1023
1024             if self.verbose:
1025                 print "Updated interface", interface_id
1026
1027     def DeleteInterfaces(self):
1028         """
1029         Delete any random network interfaces we may have added.
1030         """
1031
1032         for interface_id in self.interface_ids:
1033             self.api.DeleteInterface(interface_id)
1034
1035             if self.check:
1036                 assert not self.api.GetInterfaces([interface_id])
1037
1038             if self.verbose:
1039                 print "Deleted interface", interface_id
1040
1041         if self.check:
1042             assert not self.api.GetInterfaces(self.interface_ids)
1043
1044         self.interface_ids = []
1045         
1046     def AddIlinks (self, n):
1047         """
1048         Add random links between interfaces.
1049         """
1050
1051         for i in range (n):
1052             src = random.sample(self.interface_ids,1)[0]
1053             dst = random.sample(self.interface_ids,1)[0]
1054             ilink_id = self.api.AddIlink (src,dst,
1055                                           self.ilink_type_ids[i],
1056                                           random_ilink())
1057
1058             assert ilink_id not in self.ilink_ids
1059             self.ilink_ids.append(ilink_id)
1060
1061             if self.verbose:
1062                 print 'Added Ilink',ilink_id,' - attached interface',src,'to',dst
1063
1064             if self.check:
1065                 retrieve=GetIlinks({'src_interface_id':src,'dst_interface_id':dst,
1066                                     'tag_type_id':self.ilink_type_ids[i]})
1067                 assert ilink_id==retrieve[0]['ilink_id']
1068
1069
1070     def UpdateIlinks (self):
1071
1072         for ilink_id in self.ilink_ids:
1073             new_value=random_ilink()
1074             self.api.UpdateIlink(ilink_id,new_value)
1075
1076             if self.check:
1077                 ilink=self.api.GetIlinks([ilink_id])[0]
1078                 assert ilink['value'] == new_value
1079
1080             if self.verbose:
1081                 print 'Updated Ilink',ilink_id
1082
1083     def DeleteIlinks (self):
1084         for ilink_id in self.ilink_ids:
1085             self.api.DeleteIlink(ilink_id)
1086
1087             if self.check:
1088                 assert not self.api.GetIlinks({'ilink_id':ilink_id})
1089
1090             if self.verbose:
1091                 print 'Deleted Ilink',ilink_id
1092
1093         if self.check:
1094             assert not self.api.GetIlinks(self.ilink_ids)
1095
1096         self.ilink_ids = []
1097
1098
1099     def AddPCUs(self, per_site = 1):
1100         """
1101         Add a number of random PCUs to each site. Each node at the
1102         site will be added to a port on the PCU if AddNodes() was
1103         previously run.
1104         """
1105
1106         for site_id in self.site_ids:
1107             for i in range(per_site):
1108                 # Add PCU
1109                 pcu_fields = random_pcu()
1110                 pcu_id = self.api.AddPCU(site_id, pcu_fields)
1111
1112                 # Should return a unique pcu_id
1113                 assert pcu_id not in self.pcu_ids
1114                 self.pcu_ids.append(pcu_id)
1115
1116                 # Add each node at this site to a different port on this PCU
1117                 site = self.api.GetSites([site_id])[0]
1118                 port = randint(1, 10)
1119                 for node_id in site['node_ids']:
1120                     self.api.AddNodeToPCU(node_id, pcu_id, port)
1121                     port += 1
1122
1123                 if self.check:
1124                     # Check PCU
1125                     pcu = self.api.GetPCUs([pcu_id])[0]
1126                     for field in pcu_fields:
1127                         assert pcu[field] == pcu_fields[field]
1128
1129                 if self.verbose:
1130                     print "Added PCU", pcu_id, "to site", site_id
1131
1132     def UpdatePCUs(self):
1133         """
1134         Make random changes to any PCUs we may have added.
1135         """
1136
1137         for pcu_id in self.pcu_ids:
1138             # Update PCU
1139             pcu_fields = random_pcu()
1140             self.api.UpdatePCU(pcu_id, pcu_fields)
1141
1142             if self.check:
1143                 # Check PCU
1144                 pcu = self.api.GetPCUs([pcu_id])[0]
1145                 for field in pcu_fields:
1146                     assert pcu[field] == pcu_fields[field]
1147
1148             if self.verbose:
1149                 print "Updated PCU", pcu_id
1150
1151     def DeletePCUs(self):
1152         """
1153         Delete any random nodes we may have added.
1154         """
1155
1156         for pcu_id in self.pcu_ids:
1157             # Remove nodes from PCU
1158             pcu = self.api.GetPCUs([pcu_id])[0]
1159             for node_id in pcu['node_ids']:
1160                 self.api.DeleteNodeFromPCU(node_id, pcu_id)
1161
1162             if self.check:
1163                 pcu = self.api.GetPCUs([pcu_id])[0]
1164                 assert not pcu['node_ids']
1165
1166             self.api.DeletePCU(pcu_id)
1167
1168             if self.check:
1169                 assert not self.api.GetPCUs([pcu_id])
1170
1171             if self.verbose:
1172                 print "Deleted PCU", pcu_id
1173
1174         if self.check:
1175             assert not self.api.GetPCUs(self.pcu_ids)
1176
1177         self.pcu_ids = []
1178
1179     def AddConfFiles(self, n = 10):
1180         """
1181         Add a number of random global configuration files.
1182         """
1183
1184         conf_files = []
1185
1186         for i in range(n):
1187             # Add a random configuration file
1188             conf_files.append(random_conf_file())
1189
1190         if n:
1191             # Add a nodegroup override file
1192             nodegroup_conf_file = conf_files[0].copy()
1193             nodegroup_conf_file['source'] = randpath(255)
1194             conf_files.append(nodegroup_conf_file)
1195
1196             # Add a node override file
1197             node_conf_file = conf_files[0].copy()
1198             node_conf_file['source'] = randpath(255)
1199             conf_files.append(node_conf_file)
1200
1201         for conf_file_fields in conf_files:
1202             conf_file_id = self.api.AddConfFile(conf_file_fields)
1203
1204             # Should return a unique conf_file_id
1205             assert conf_file_id not in self.conf_file_ids
1206             self.conf_file_ids.append(conf_file_id)
1207
1208             # Add to nodegroup
1209             if conf_file_fields == nodegroup_conf_file and self.nodegroup_ids:
1210                 nodegroup_id = random.sample(self.nodegroup_ids, 1)[0]
1211                 self.api.AddConfFileToNodeGroup(conf_file_id, nodegroup_id)
1212             else:
1213                 nodegroup_id = None
1214
1215             # Add to node
1216             if conf_file_fields == node_conf_file and self.node_ids:
1217                 node_id = random.sample(self.node_ids, 1)[0]
1218                 self.api.AddConfFileToNode(conf_file_id, node_id)
1219             else:
1220                 node_id = None
1221
1222             if self.check:
1223                 # Check configuration file
1224                 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1225                 for field in conf_file_fields:
1226                     assert conf_file[field] == conf_file_fields[field]
1227
1228             if self.verbose:
1229                 print "Added configuration file", conf_file_id,
1230                 if nodegroup_id is not None:
1231                     print "to node group", nodegroup_id,
1232                 elif node_id is not None:
1233                     print "to node", node_id,
1234                 print
1235
1236     def UpdateConfFiles(self):
1237         """
1238         Make random changes to any configuration files we may have added.
1239         """
1240
1241         for conf_file_id in self.conf_file_ids:
1242             # Update configuration file
1243             conf_file_fields = random_conf_file()
1244             # Do not update dest so that it remains an override if set
1245             if 'dest' in conf_file_fields:
1246                 del conf_file_fields['dest']
1247             self.api.UpdateConfFile(conf_file_id, conf_file_fields)
1248
1249             if self.check:
1250                 # Check configuration file
1251                 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1252                 for field in conf_file_fields:
1253                     assert conf_file[field] == conf_file_fields[field]
1254
1255             if self.verbose:
1256                 print "Updated configuration file", conf_file_id
1257
1258     def DeleteConfFiles(self):
1259         """
1260         Delete any random configuration files we may have added.
1261         """
1262
1263         for conf_file_id in self.conf_file_ids:
1264             self.api.DeleteConfFile(conf_file_id)
1265
1266             if self.check:
1267                 assert not self.api.GetConfFiles([conf_file_id])
1268
1269             if self.verbose:
1270                 print "Deleted configuration file", conf_file_id
1271
1272         if self.check:
1273             assert not self.api.GetConfFiles(self.conf_file_ids)
1274
1275         self.conf_file_ids = []
1276
1277     def AddTagTypes(self,n_sa,n_ng,n_il):
1278         """
1279         Add as many tag types as there are nodegroups, 
1280         will use tagvalue=yes for each nodegroup
1281         """
1282
1283         roles = self.api.GetRoles()
1284         if not roles:
1285             raise Exception, "No roles"
1286         role_ids = [role['role_id'] for role in roles]
1287
1288         for i in range (n_sa + n_ng + n_il):
1289             tag_type_fields = random_tag_type (role_ids)
1290             tag_type_id = self.api.AddTagType (tag_type_fields)
1291
1292             assert tag_type_id not in \
1293                 self.slice_type_ids + \
1294                 self.nodegroup_type_ids + \
1295                 self.ilink_type_ids
1296             
1297             if i < n_sa:
1298                 self.slice_type_ids.append(tag_type_id)
1299             elif i < n_sa+n_ng :
1300                 self.nodegroup_type_ids.append(tag_type_id)
1301             else:
1302                 self.ilink_type_ids.append(tag_type_id)
1303
1304             if self.check:
1305                 tag_type = self.api.GetTagTypes([tag_type_id])[0]
1306                 for field in tag_type_fields:
1307                     assert tag_type[field] == tag_type_fields[field]
1308             if self.verbose:
1309                 print "Updated slice attribute type", tag_type_id
1310
1311     def UpdateTagTypes(self):
1312         """
1313         Make random changes to any slice attribute types we may have added.
1314         """
1315
1316         roles = self.api.GetRoles()
1317         if not roles:
1318             raise Exception, "No roles"
1319         role_ids = [role['role_id'] for role in roles]
1320
1321         for tag_type_id in self.slice_type_ids + self.nodegroup_type_ids + self.ilink_type_ids:
1322             # Update slice attribute type
1323             tag_type_fields = random_tag_type(role_ids)
1324             self.api.UpdateTagType(tag_type_id, tag_type_fields)
1325
1326             if self.check:
1327                 # Check slice attribute type
1328                 tag_type = self.api.GetTagTypes([tag_type_id])[0]
1329                 for field in tag_type_fields:
1330                     assert tag_type[field] == tag_type_fields[field]
1331             if self.verbose:
1332                 print "Updated slice attribute type", tag_type_id
1333
1334     def DeleteTagTypes(self):
1335         """
1336         Delete any random slice attribute types we may have added.
1337         """
1338
1339         for tag_type_id in self.slice_type_ids + self.nodegroup_type_ids + self.ilink_type_ids:
1340             self.api.DeleteTagType(tag_type_id)
1341
1342             if self.check:
1343                 assert not self.api.GetTagTypes([tag_type_id])
1344
1345             if self.verbose:
1346                 print "Deleted slice attribute type", tag_type_id
1347
1348         if self.check:
1349             assert not self.api.GetTagTypes(self.slice_type_ids+self.nodegroup_type_ids+self.ilink_type_ids)
1350
1351         self.slice_type_ids = []
1352         self.nodegroup_type_ids = []
1353
1354     def AddSlices(self, per_site = 10):
1355         """
1356         Add a number of random slices per site.
1357         """
1358
1359         for site in self.api.GetSites(self.site_ids):
1360             for i in range(min(per_site, site['max_slices'])):
1361                 # Add slice
1362                 slice_fields = random_slice(site['login_base'])
1363                 slice_id = self.api.AddSlice(slice_fields)
1364
1365                 # Should return a unique slice_id
1366                 assert slice_id not in self.slice_ids
1367                 self.slice_ids.append(slice_id)
1368
1369                 # Add slice to a random set of nodes
1370                 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1371                 if node_ids:
1372                     self.api.AddSliceToNodes(slice_id, node_ids)
1373
1374                 # Add random set of site users to slice
1375                 person_ids = random.sample(site['person_ids'], randint(0, len(site['person_ids'])))
1376                 for person_id in person_ids:
1377                     self.api.AddPersonToSlice(person_id, slice_id)
1378
1379                 if self.check:
1380                     # Check slice
1381                     slice = self.api.GetSlices([slice_id])[0]
1382                     for field in slice_fields:
1383                         assert slice[field] == slice_fields[field]
1384
1385                     assert set(node_ids) == set(slice['node_ids'])
1386                     assert set(person_ids) == set(slice['person_ids'])
1387
1388                 if self.verbose:
1389                     print "Added slice", slice_id, "to site", site['site_id'],
1390                     if node_ids:
1391                         print "and nodes", node_ids,
1392                     print
1393                     if person_ids:
1394                         print "Added users", site['person_ids'], "to slice", slice_id
1395
1396     def UpdateSlices(self):
1397         """
1398         Make random changes to any slices we may have added.
1399         """
1400
1401         for slice_id in self.slice_ids:
1402             # Update slice
1403             slice_fields = random_slice("unused")
1404             # Cannot change slice name
1405             if 'name' in slice_fields:
1406                 del slice_fields['name']
1407             self.api.UpdateSlice(slice_id, slice_fields)
1408
1409             slice = self.api.GetSlices([slice_id])[0]
1410
1411             # Add slice to a random set of nodes
1412             node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1413             self.api.AddSliceToNodes(slice_id, list(set(node_ids) - set(slice['node_ids'])))
1414             self.api.DeleteSliceFromNodes(slice_id, list(set(slice['node_ids']) - set(node_ids)))
1415
1416             # Add random set of users to slice
1417             person_ids = random.sample(self.person_ids, randint(0, len(self.person_ids)))
1418             for person_id in (set(person_ids) - set(slice['person_ids'])):
1419                 self.api.AddPersonToSlice(person_id, slice_id)
1420             for person_id in (set(slice['person_ids']) - set(person_ids)):
1421                 self.api.DeletePersonFromSlice(person_id, slice_id)
1422
1423             if self.check:
1424                 slice = self.api.GetSlices([slice_id])[0]
1425                 for field in slice_fields:
1426                     assert slice[field] == slice_fields[field]
1427                 assert set(node_ids) == set(slice['node_ids'])
1428                 assert set(person_ids) == set(slice['person_ids'])
1429
1430             if self.verbose:
1431                 print "Updated slice", slice_id
1432                 print "Added nodes", node_ids, "to slice", slice_id
1433                 print "Added persons", person_ids, "to slice", slice_id
1434
1435     def DeleteSlices(self):
1436         """
1437         Delete any random slices we may have added.
1438         """
1439
1440         for slice_id in self.slice_ids:
1441             self.api.DeleteSlice(slice_id)
1442
1443             if self.check:
1444                 assert not self.api.GetSlices([slice_id])
1445
1446             if self.verbose:
1447                 print "Deleted slice", slice_id
1448
1449         if self.check:
1450             assert not self.api.GetSlices(self.slice_ids)
1451
1452         self.slice_ids = []
1453
1454     def AddSliceTags(self, per_slice = 2):
1455         """
1456         Add a number of random slices per site.
1457         """
1458
1459         if not self.slice_type_ids:
1460             return
1461
1462         for slice_id in self.slice_ids:
1463             slice = self.api.GetSlices([slice_id])[0]
1464
1465             for i in range(per_slice):
1466                 # Set a random slice/sliver attribute
1467                 for tag_type_id in random.sample(self.slice_type_ids, 1):
1468                     value = randstr(16, letters + '_' + digits)
1469                     # Make it a sliver attribute with 50% probability
1470                     if slice['node_ids']:
1471                         node_id = random.sample(slice['node_ids'] + [None] * len(slice['node_ids']), 1)[0]
1472                     else:
1473                         node_id = None
1474
1475                     # Add slice attribute
1476                     if node_id is None:
1477                         slice_tag_id = self.api.AddSliceTag(slice_id, tag_type_id, value)
1478                     else:
1479                         slice_tag_id = self.api.AddSliceTag(slice_id, tag_type_id, value, node_id)
1480
1481                     # Should return a unique slice_tag_id
1482                     assert slice_tag_id not in self.slice_tag_ids
1483                     self.slice_tag_ids.append(slice_tag_id)
1484
1485                     if self.check:
1486                         # Check slice attribute
1487                         slice_tag = self.api.GetSliceTags([slice_tag_id])[0]
1488                         for field in 'tag_type_id', 'slice_id', 'node_id', 'slice_tag_id', 'value':
1489                             assert slice_tag[field] == locals()[field]
1490
1491                     if self.verbose:
1492                         print "Added slice attribute", slice_tag_id, "of type", tag_type_id,
1493                         if node_id is not None:
1494                             print "to node", node_id,
1495                         print
1496                         
1497     def UpdateSliceTags(self):
1498         """
1499         Make random changes to any slice attributes we may have added.
1500         """
1501
1502         for slice_tag_id in self.slice_tag_ids:
1503             # Update slice attribute
1504             value = randstr(16, letters + '_' + digits)
1505             self.api.UpdateSliceTag(slice_tag_id, value)
1506
1507             # Check slice attribute again
1508             slice_tag = self.api.GetSliceTags([slice_tag_id])[0]
1509             assert slice_tag['value'] == value
1510
1511             if self.verbose:
1512                 print "Updated slice attribute", slice_tag_id
1513
1514     def DeleteSliceTags(self):
1515         """
1516         Delete any random slice attributes we may have added.
1517         """
1518
1519         for slice_tag_id in self.slice_tag_ids:
1520             self.api.DeleteSliceTag(slice_tag_id)
1521
1522             if self.check:
1523                 assert not self.api.GetSliceTags([slice_tag_id])
1524
1525             if self.verbose:
1526                 print "Deleted slice attribute", slice_tag_id
1527
1528         if self.check:
1529             assert not self.api.GetSliceTags(self.slice_tag_ids)
1530
1531         self.slice_tag_ids = []
1532
1533 def main():
1534     parser = OptionParser()
1535     parser.add_option("-c", "--check", action = "store_true", default = False, 
1536                       help = "Check most actions (default: %default)")
1537     parser.add_option("-q", "--quiet", action = "store_true", default = False, 
1538                       help = "Be quiet (default: %default)")
1539     parser.add_option("-p","--preserve", action="store_true", default =False,
1540                       help = "Do not delete created objects")
1541     parser.add_option("-t", "--tiny", action = "store_true", default = False, 
1542                       help = "Run a tiny test (default: %default)")
1543     (options, args) = parser.parse_args()
1544
1545     test = Test(api = Shell(),
1546                 check = options.check,
1547                 verbose = not options.quiet,
1548                 preserve = options.preserve)
1549
1550     if options.tiny:
1551         params = Test.tiny
1552     else:
1553         params = Test.default
1554
1555     test.Run(**params)
1556
1557 if __name__ == "__main__":
1558     main()