28dffb0029476e5cb9234da8e00f0a67da1ce0d7
[plcapi.git] / PLC / Methods / UpdateLeases.py
1 from PLC.Faults import *
2 from PLC.Method import Method
3 from PLC.Parameter import Parameter, Mixed
4 from PLC.Auth import Auth
5
6 from PLC.Timestamp import Timestamp, Duration
7
8 from PLC.Leases import Lease, Leases
9 from PLC.Slices import Slice, Slices
10
11 can_update = lambda (field, value): field in ['t_from', 't_until', 'duration']
12
13 class UpdateLeases(Method):
14     """
15     Updates the parameters of a (set of) existing lease(s) with the values in
16     lease_fields; specifically this applies to the timeslot definition.
17     As a convenience you may, in addition to the t_from and t_until fields,
18     you can also set the 'duration' field.
19
20     Users may only update leases attached to their slices.
21     PIs may update any of the leases for slices at their sites, or any
22     slices of which they are members. Admins may update any lease.
23
24     Returns a dict of successfully updated lease_ids and error messages.
25     """
26
27     roles = ['admin', 'pi', 'tech', 'user']
28
29     lease_fields = dict(filter(can_update, Lease.fields.items()))
30
31     accepts = [
32         Auth(),
33         Mixed (Lease.fields['lease_id'],
34                [Lease.fields['lease_id']]),
35         lease_fields
36         ]
37
38     returns = Parameter(dict, " 'updated_ids' is the list ids updated, 'errors' is a list of error strings")
39
40     debug=False
41 #    debug=True
42
43     def call(self, auth, lease_ids, input_fields):
44         input_fields = dict(filter(can_update, input_fields.items()))
45
46         if 'duration' in input_fields:
47             if 't_from' in input_fields and 't_until' in input_fields:
48                 raise PLCInvalidArgument, "Cannot set t_from AND t_until AND duration"
49             # specify 'duration':0 to keep duration unchanged
50             if input_fields['duration'] : input_fields['duration']=Duration.validate(input_fields['duration'])
51
52         # Get lease information
53         leases = Leases(self.api, lease_ids)
54         if not leases:
55             raise PLCInvalidArgument, "No such leases %r"%lease_ids
56
57         # fetch related slices
58         slices = Slices(self.api, [ lease['slice_id'] for lease in leases],['slice_id','person_ids'])
59         # create hash on slice_id
60         slice_map = dict ( [ (slice['slice_id'],slice) for slice in slices ] )
61
62         updated_ids=[]
63         errors=[]
64
65         lease_ids=[lease['lease_id'] for lease in leases]
66         for lease in leases:
67
68             if 'admin' not in self.caller['roles']:
69                 slice=slice_map[lease['slice_id']]
70                 # check slices only once
71                 if not slice.has_key('verified'):
72                     if self.caller['person_id'] in slice['person_ids']:
73                         pass
74                     elif 'pi' not in self.caller['roles']:
75                         raise PLCPermissionDenied, "Not a member of slice %r"%slice['name']
76                     elif slice['site_id'] not in self.caller['site_ids']:
77                         raise PLCPermissionDenied, "Slice %r not associated with any of your sites"%slice['name']
78             slice['verified']=True
79
80             try:
81                 # we've ruled out already the case where all 3 (from, to, duration) where specified
82                 if 'duration' not in input_fields:
83                     lease_fields=input_fields
84                 else:
85                     # all arithmetics on longs..
86                     duration=Duration.validate(input_fields['duration'])
87                     # specify 'duration':0 to keep duration unchanged
88                     if not duration:
89                         duration = Timestamp.cast_long(lease['t_until'])-Timestamp.cast_long(lease['t_from'])
90                     if 't_from' in input_fields:
91                         lease_fields={'t_from':input_fields['t_from'],
92                                       't_until':Timestamp.cast_long(input_fields['from'])+duration}
93                     elif 't_until' in input_fields:
94                         lease_fields={'t_from':Timestamp.cast_long(input_fields['t_until'])-duration,
95                                       't_until':input_fields['t_until']}
96                     else:
97                         lease_fields={'t_until':Timestamp.cast_long(lease['t_from'])+duration}
98                 if UpdateLeases.debug:
99                     print 'lease_fields',lease_fields
100                     for k in [ 't_from', 't_until'] :
101                         if k in lease_fields:
102                             print k,'aka',Timestamp.sql_validate_utc(lease_fields[k])
103
104                 lease.update(lease_fields)
105                 lease.sync()
106                 updated_ids.append(lease['lease_id'])
107             except Exception,e:
108                 errors.append("Could not update lease %d - check new time limits ? -- %r"%(lease['lease_id'],e))
109
110         # Logging variables
111         self.event_objects = {'Lease': updated_ids}
112         self.message = 'lease %r updated: %s' %  (lease_ids, ", ".join(input_fields.keys()))
113
114         return {'updated_ids' : updated_ids,
115                 'errors' : errors }