3 from PLC.Faults import *
4 from PLC.Method import Method
5 from PLC.Parameter import Parameter, Mixed
6 from PLC.Auth import Auth
8 from PLC.Timestamp import Timestamp, Duration
10 from PLC.Leases import Lease, Leases
11 from PLC.Slices import Slice, Slices
13 can_update = lambda field_value: field_value[0] in ['t_from', 't_until', 'duration']
16 class UpdateLeases(Method):
18 Updates the parameters of a (set of) existing lease(s) with the values in
19 lease_fields; specifically this applies to the timeslot definition.
20 As a convenience you may, in addition to the t_from and t_until fields,
21 you can also set the 'duration' field.
23 Users may only update leases attached to their slices.
24 PIs may update any of the leases for slices at their sites, or any
25 slices of which they are members. Admins may update any lease.
27 Returns a dict of successfully updated lease_ids and error messages.
30 roles = ['admin', 'pi', 'tech', 'user']
32 lease_fields = dict(list(filter(can_update, list(Lease.fields.items()))))
36 Mixed(Lease.fields['lease_id'],
37 [Lease.fields['lease_id']]),
43 " 'updated_ids' is the list ids updated,"
44 "'errors' is a list of error strings")
49 def call(self, auth, lease_ids, input_fields):
50 input_fields = dict(list(filter(can_update, list(input_fields.items()))))
52 if 'duration' in input_fields:
53 if 't_from' in input_fields and 't_until' in input_fields:
54 raise PLCInvalidArgument(
55 "Cannot set t_from AND t_until AND duration")
56 # specify 'duration':0 to keep duration unchanged
57 if input_fields['duration']:
58 input_fields['duration'] = Duration.validate(
59 input_fields['duration'])
61 # Get lease information
62 leases = Leases(self.api, lease_ids)
64 raise PLCInvalidArgument("No such leases {}".format(lease_ids))
66 # fetch related slices
67 slices = Slices(self.api,
68 [lease['slice_id'] for lease in leases],
69 ['slice_id', 'person_ids'])
70 # create hash on slice_id
71 slice_map = dict([(slice['slice_id'], slice) for slice in slices])
76 lease_ids = [lease['lease_id'] for lease in leases]
79 if 'admin' not in self.caller['roles']:
80 slice = slice_map[lease['slice_id']]
81 # check slices only once
82 if 'verified' not in slice:
83 if self.caller['person_id'] in slice['person_ids']:
84 slice['verified'] = True
85 elif 'pi' not in self.caller['roles']:
86 raise PLCPermissionDenied(
87 "Not a member of slice {}".format(slice['name']))
88 elif slice['site_id'] not in self.caller['site_ids']:
89 raise PLCPermissionDenied(
90 "Slice {} not associated with any of your sites"
91 .format(slice['name']))
94 # we've ruled out already the case where all 3 (from, to,
95 # duration) where specified
96 if 'duration' not in input_fields:
97 lease_fields = input_fields
99 # all arithmetics on longs..
100 duration = Duration.validate(input_fields['duration'])
101 # specify 'duration':0 to keep duration unchanged
103 duration = Timestamp.cast_long(
105 - Timestamp.cast_long(lease['t_from'])
106 if 't_from' in input_fields:
108 't_from': input_fields['t_from'],
109 't_until': Timestamp.cast_long(
110 input_fields['from']) + duration}
111 elif 't_until' in input_fields:
113 't_from': Timestamp.cast_long(
114 input_fields['t_until']) - duration,
115 't_until': input_fields['t_until']}
117 lease_fields = {'t_until': Timestamp.cast_long(
118 lease['t_from']) + duration}
119 if UpdateLeases.debug:
120 for k in ['t_from', 't_until']:
121 if k in lease_fields:
122 print(k, 'aka', Timestamp.sql_validate_utc(
125 lease.update(lease_fields)
127 updated_ids.append(lease['lease_id'])
128 except Exception as e:
130 "Could not update lease {} - check new time limits ? -- {}"
131 .format(lease['lease_id'], e))
134 self.event_objects = {'Lease': updated_ids}
135 self.message = 'lease {} updated: {}'\
136 .format(lease_ids, ", ".join(list(input_fields.keys())))
138 return {'updated_ids': updated_ids,