598586c02574a90175bb114dedf460d154491e3a
[raven.git] / apps / gacks / gacksenforce_test.py
1 import time
2
3 from gacksaccount import GacksAccount
4 from gacksaccountmanager import GacksAccountManager
5 from gackscalendar_mysql import GacksMySQLCalendar
6 from gacksresource import GacksResourceDirectory
7 from gacksenforce import GacksEnforcer
8 from gackspolicy import GacksPolicyDirectory
9 from gackshandle import GacksHandle, GacksRecord
10 from gacksexcep import *
11
12 HOUR=60*60
13 DAY=24*60*60
14
15 CORES_PER_NODE=11
16 NODE1=CORES_PER_NODE*0
17 NODE2=CORES_PER_NODE*1
18 NODE3=CORES_PER_NODE*2
19 NODE4=CORES_PER_NODE*3
20 NODE5=CORES_PER_NODE*4
21 NODE6=CORES_PER_NODE*5
22 NODE7=CORES_PER_NODE*6
23 NODE8=CORES_PER_NODE*7
24 NODE9=CORES_PER_NODE*8
25 NODE10=CORES_PER_NODE*9
26 NODE11=CORES_PER_NODE*10
27
28 class test:
29     def __init__(self):
30         self.accounts = GacksAccountManager()
31         self.policies = GacksPolicyDirectory(dir="./policy.d")
32         self.resources = GacksResourceDirectory(dir="./resources.d")
33         self.calendar = GacksMySQLCalendar(tableName = "gacksaccount_test")
34
35         self.calendar.reset()
36
37         self.init_accounts()
38
39         self.enforcer = GacksEnforcer(self.accounts, self.policies, self.calendar, self.resources)
40
41         self.test_goodStanding()
42         self.test_kind()
43         self.test_duration()
44         self.test_endtime()
45         self.test_max_on_node()
46         self.test_max_concurrent()
47         self.test_bucket()
48
49     def handle_to_rec(self, h, allocatorHRNs):
50         r = GacksRecord(id=h.id, unitStart=h.unitStart, unitStop=h.unitStop,
51                         timeStart=h.timeStart, timeStop=h.timeStop, allocatorHRNs=allocatorHRNs)
52         return r
53
54     def init_accounts(self):
55         # initialize some accounts
56         self.accounts.delete_account("plc.test.gold", "user")
57         self.accounts.delete_account("plc.test.silver", "user")
58         self.accounts.delete_account("plc.test.best", "user")
59         self.accounts.delete_account("plc.test.test1", "user")
60         self.accounts.delete_account("plc.test.test1b", "user")
61         self.accounts.delete_account("plc.test.test1c", "user")
62         self.accounts.delete_account("plc.test.test1d", "user")
63         self.accounts.delete_account("plc.test.test2", "user")
64         self.accounts.delete_account("plc.test.test2", "bucket")
65
66         self.gold=self.accounts.new_account("plc.test.gold", "user")
67         self.gold.level="gold"
68         self.gold.goodStanding=True
69         self.gold.commit()
70
71         self.silver=self.accounts.new_account("plc.test.silver", "user")
72         self.silver.level="silver"
73         self.silver.goodStanding=True
74         self.silver.commit()
75
76         self.best=self.accounts.new_account("plc.test.best", "user")
77         self.best.goodStanding=True
78         self.best.commit()
79
80         self.test1=self.accounts.new_account("plc.test.test1", "user")
81         self.test1.level="test_policy_1"
82         self.test1.goodStanding=True
83         self.test1.commit()
84
85         self.test1b=self.accounts.new_account("plc.test.test1b", "user")
86         self.test1b.level="test_policy_1"
87         self.test1b.goodStanding=True
88         self.test1b.commit()
89
90         self.test1c=self.accounts.new_account("plc.test.test1c", "user")
91         self.test1c.level="test_policy_1"
92         self.test1c.multiplier=2
93         self.test1c.goodStanding=True
94         self.test1c.commit()
95
96         self.test1d=self.accounts.new_account("plc.test.test1d", "user")
97         self.test1d.level="test_policy_1"
98         self.test1d.goodStanding=False
99         self.test1d.commit()
100
101         self.test2=self.accounts.new_account("plc.test.test2", "user")
102         self.test2.level="test_policy_2"
103         self.test2.goodStanding=True
104         self.test2.commit()
105
106     def test_kind(self):
107         t = time.time()
108
109         # calendar day, should be okay
110         h = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+1*24*60*60, unitStart=1, unitStop=2)
111         self.enforcer.check("plc.test.test1", [h], "calendar")
112
113         # asap, should fail
114         h = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+1*24*60*60, unitStart=1, unitStop=2)
115         try:
116             self.enforcer.check("plc.test.test1", [h], "asap")
117         except GacksEnforcerNoReservation:
118             pass
119         else:
120             raise "Failed to raise GacksEnforcerNoReservation"
121
122     def test_duration(self):
123         t = time.time()
124
125         # 1 day, should be okay
126         h = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+1*24*60*60, unitStart=1, unitStop=2)
127         self.enforcer.check("plc.test.test1", [h])
128
129         # 5 days, ought to just fit
130         h = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+5*24*60*60, unitStart=1, unitStop=2)
131         self.enforcer.check("plc.test.test1", [h])
132
133         # 5 days + 1 second, too long
134         try:
135             h = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+5*24*60*60+1, unitStart=1, unitStop=2)
136             self.enforcer.check("plc.test.test1", [h])
137         except GacksEnforcerDurationTooLong:
138             pass
139         else:
140             raise "Failed to raise GacksEnforcerDurationTooLong"
141
142     def test_endtime(self):
143         t = time.time()
144
145         # 1 day from now, should be okay
146         h = GacksHandle(id="plc.vicci.cores", timeStart=t+5*DAY, timeStop=t+6*DAY, unitStart=1, unitStop=2)
147         self.enforcer.check("plc.test.test1", [h])
148
149         # 11 days from now, should be bad
150         try:
151             h = GacksHandle(id="plc.vicci.cores", timeStart=t+10*DAY, timeStop=t+11*DAY, unitStart=1, unitStop=2)
152             self.enforcer.check("plc.test.test1", [h])
153         except GacksEnforcerEndDateBeyondLimit:
154             pass
155         else:
156             raise "Failed to raise GacksEnforcerEndDateBeyondLimit"
157
158     def test_max_on_node(self):
159         t = time.time()
160
161         # 3 units is okay
162         h = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=1, unitStop=4)
163         self.enforcer.check("plc.test.test1", [h])
164
165         # 4 units is bad
166         try:
167             h = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=1, unitStop=5)
168             self.enforcer.check("plc.test.test1", [h])
169         except GacksEnforcerTooManyOnNode:
170             pass
171         else:
172             raise "Failed to raise GacksEnforcerTooManyOnNode"
173
174         # 3 units is okay
175         h1 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=1, unitStop=2)
176         h2 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=5, unitStop=7)
177         self.enforcer.check("plc.test.test1", [h1,h2])
178
179         # 4 units is bad
180         try:
181             h1 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=1, unitStop=3)
182             h2 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=5, unitStop=7)
183             self.enforcer.check("plc.test.test1", [h1,h2])
184         except GacksEnforcerTooManyOnNode:
185             pass
186         else:
187             raise "Failed to raise GacksEnforcerTooManyOnNode"
188
189         # 3 units each on 2 different nodes is okay
190         h1 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=1, unitStop=4)
191         h2 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=13, unitStop=16)
192         self.enforcer.check("plc.test.test1", [h1,h2])
193
194         # lets put some stuff in the calendar
195         r1 = GacksRecord(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=1, unitStop=2, allocatorHRNs=["plc.test.test1"])
196         self.calendar.insert_record(r1)
197
198         # 3 units is okay
199         h2 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=5, unitStop=7)
200         self.enforcer.check("plc.test.test1", [h2])
201
202         # 4 units is bad
203         try:
204             h2 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=5, unitStop=8)
205             self.enforcer.check("plc.test.test1", [h2])
206         except GacksEnforcerTooManyOnNode:
207             pass
208         else:
209             raise "Failed to raise GacksEnforcerTooManyOnNode"
210
211         # clean out the changes we made to the calendar
212         self.calendar.reset()
213
214     def test_max_concurrent(self):
215         t = time.time()
216
217         # 3 units per node, 9 units total is okay
218         h1 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=NODE1, unitStop=NODE1+3)
219         h2 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=NODE2, unitStop=NODE2+3)
220         h3 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=NODE3, unitStop=NODE3+3)
221         self.enforcer.check("plc.test.test1", [h1,h2,h3])
222
223         # 10 units total is bad
224         h4 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=NODE4, unitStop=NODE4+1)
225         try:
226             self.enforcer.check("plc.test.test1", [h1,h2,h3,h4])
227         except GacksEnforcerTooManyConcurrent:
228             pass
229         else:
230             raise "Failed to raise GacksEnforcerTooManyConcurrent"
231
232         # put some in the database
233         r1 = self.handle_to_rec(h1, ["plc.test.test1"])
234         r2 = self.handle_to_rec(h2, ["plc.test.test1"])
235         r3 = self.handle_to_rec(h3, ["plc.test.test1"])
236
237         self.calendar.insert_record(r1)
238         self.calendar.insert_record(r2)
239         self.calendar.insert_record(r3)
240
241         # units to a different user should be okay
242         h4 = GacksHandle(id="plc.vicci.cores", timeStart=t+DAY, timeStop=t+2*DAY, unitStart=NODE4, unitStop=NODE4+1)
243         self.enforcer.check("plc.test.test1b", [h4])
244
245         # units at a different time should be okay
246         h4 = GacksHandle(id="plc.vicci.cores", timeStart=t+DAY, timeStop=t+2*DAY, unitStart=NODE4, unitStop=NODE4+1)
247         self.enforcer.check("plc.test.test1", [h4])
248
249         # 10 units at the same time is bad
250         h4 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+1*DAY, unitStart=NODE4, unitStop=NODE4+1)
251         try:
252             self.enforcer.check("plc.test.test1", [h4])
253         except GacksEnforcerTooManyConcurrent:
254             pass
255         else:
256             raise "Failed to raise GacksEnforcerTooManyConcurrent"
257
258         # multiplier = 2, then we can do up to 18
259         h5 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=NODE5, unitStop=NODE5+3)
260         h6 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=NODE6, unitStop=NODE6+3)
261         h7 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=NODE7, unitStop=NODE7+3)
262         self.enforcer.check("plc.test.test1c", [h1,h2,h3,h5,h6,h7])
263
264         # but not 19
265         try:
266            self.enforcer.check("plc.test.test1c", [h1,h2,h3,h5,h6,h7,h4])
267         except GacksEnforcerTooManyConcurrent:
268             pass
269         else:
270             raise "Failed to raise GacksEnforcerTooManyConcurrent"
271
272         self.calendar.reset()
273
274     def test_goodStanding(self):
275         t = time.time()
276
277         # 3 units per node, 9 units total is okay
278         h1 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+DAY, unitStart=NODE1, unitStop=NODE1+3)
279
280         try:
281             self.enforcer.check("plc.test.test1d", [h1])
282         except GacksEnforcerNotGoodStanding:
283             pass
284         else:
285             raise "Failed to raise GacksEnforcerNotGoodStanding"
286
287     def test_bucket(self):
288         t = time.time()
289
290         # lets work on an hour boundary
291         t = ((int(t)/3600) + 1) * 3600
292
293         h1 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+HOUR, unitStart=NODE1, unitStop=NODE1+3)
294
295         # 3 units is okay
296         self.enforcer.check("plc.test.test2", [h1])
297
298         r1 = self.handle_to_rec(h1, ["plc.test.test2"])
299         self.calendar.insert_record(r1)
300
301         h2 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+HOUR, unitStart=NODE2, unitStop=NODE2+3)
302
303         try:
304             # 6 units is too many
305             self.enforcer.check("plc.test.test2", [h2])
306         except GacksEnforcerBucketUnderflow:
307             pass
308         else:
309             raise "Failed to raise GacksEnforcerBuckerUnderflow"
310
311         h3 = GacksHandle(id="plc.vicci.cores", timeStart=t+HOUR, timeStop=t+2*HOUR, unitStart=NODE3, unitStop=NODE3+3)
312
313         # 3 units followed by 3 units is okay
314         self.enforcer.check("plc.test.test2", [h3])
315
316         r3 = self.handle_to_rec(h3, ["plc.test.test2"])
317         self.calendar.insert_record(r3)
318
319         # there should be 5 units available at time t+2hours
320         #    5 starting units
321         #   +6 bucket filled units
322         #   -6 allocated units
323         #   =5 units left
324
325         h4= GacksHandle(id="plc.vicci.cores", timeStart=t+2*HOUR, timeStop=t+3*HOUR, unitStart=NODE4, unitStop=NODE4+5)
326
327         # 5 units is okay
328         self.enforcer.check("plc.test.test2", [h4])
329
330         r4 = self.handle_to_rec(h4, ["plc.test.test2"])
331         self.calendar.insert_record(r4)
332
333         # 1 unit anywhere else should be a problem
334         h5 = GacksHandle(id="plc.vicci.cores", timeStart=t, timeStop=t+HOUR, unitStart=NODE4, unitStop=NODE4+1)
335         try:
336             self.enforcer.check("plc.test.test2", [h5])
337         except GacksEnforcerBucketUnderflow:
338             pass
339         else:
340             raise "Failed to raise GacksEnforcerBuckerUnderflow"
341
342         h5 = GacksHandle(id="plc.vicci.cores", timeStart=t+HOUR, timeStop=t+2*HOUR, unitStart=NODE4, unitStop=NODE4+1)
343         try:
344             self.enforcer.check("plc.test.test2", [h5])
345         except GacksEnforcerBucketUnderflow:
346             pass
347         else:
348             raise "Failed to raise GacksEnforcerBuckerUnderflow"
349
350         h5 = GacksHandle(id="plc.vicci.cores", timeStart=t+2*HOUR, timeStop=t+3*HOUR, unitStart=NODE4, unitStop=NODE4+1)
351         try:
352             self.enforcer.check("plc.test.test2", [h5])
353         except GacksEnforcerBucketUnderflow:
354             pass
355         else:
356             raise "Failed to raise GacksEnforcerBuckerUnderflow"
357
358         # try some long reservations
359
360         # 2 nodes for 10 days
361         h6 = GacksHandle(id="plc.vicci.cores", timeStart=t+DAY, timeStop=t+11*DAY, unitStart=NODE6, unitStop=NODE6+2)
362         self.enforcer.check("plc.test.test2", [h6])
363         r6 = self.handle_to_rec(h6, ["plc.test.test2"])
364         self.calendar.insert_record(r6)
365
366         # 1 nodes for 2 days each, overlapped with the 3-day reservation
367         h7 = GacksHandle(id="plc.vicci.cores", timeStart=t+2*DAY, timeStop=t+4*DAY, unitStart=NODE7, unitStop=NODE7+1)
368         h8 = GacksHandle(id="plc.vicci.cores", timeStart=t+6*DAY, timeStop=t+8*DAY, unitStart=NODE8, unitStop=NODE8+1)
369         self.enforcer.check("plc.test.test2", [h7])
370         r7 = self.handle_to_rec(h7, ["plc.test.test2"])
371         self.enforcer.check("plc.test.test2", [h8])
372         r8 = self.handle_to_rec(h8, ["plc.test.test2"])
373         self.calendar.insert_record(r7)
374
375         # 2 additional nodes should not cause a problem
376         h9 = GacksHandle(id="plc.vicci.cores", timeStart=t+2*DAY+5*HOUR, timeStop=t+2*DAY+6*HOUR, unitStart=NODE9, unitStop=NODE9+2)
377         self.enforcer.check("plc.test.test2", [h9])
378         r9 = self.handle_to_rec(h9, ["plc.test.test2"])
379         self.calendar.insert_record(r9)
380
381         # 1 additional node (total of 2+1+2+1 == 6) should cause a bucket underflow
382         h10 = GacksHandle(id="plc.vicci.cores", timeStart=t+2*DAY+5*HOUR, timeStop=t+2*DAY+6*HOUR, unitStart=NODE10, unitStop=NODE10+1)
383         try:
384             self.enforcer.check("plc.test.test2", [h10])
385         except GacksEnforcerBucketUnderflow:
386             pass
387         else:
388             raise "Failed to raise GacksEnforcerBuckerUnderflow"
389
390         # insert a big empty period to test handling gaps efficiently
391         h11 = GacksHandle(id="plc.vicci.cores", timeStart=t+5000*DAY, timeStop=t+5001*DAY, unitStart=NODE11, unitStop=NODE11+2)
392         self.enforcer.check("plc.test.test2", [h11])
393
394
395
396 test()