formatted the 'db' script using vscode
[plcapi.git] / PLC / Methods / UpdateLeases.py
1
2
3 from PLC.Faults import *
4 from PLC.Method import Method
5 from PLC.Parameter import Parameter, Mixed
6 from PLC.Auth import Auth
7
8 from PLC.Timestamp import Timestamp, Duration
9
10 from PLC.Leases import Lease, Leases
11 from PLC.Slices import Slice, Slices
12
13 can_update = lambda field_value: field_value[0] in ['t_from', 't_until', 'duration']
14
15
16 class UpdateLeases(Method):
17     """
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.
22
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.
26
27     Returns a dict of successfully updated lease_ids and error messages.
28     """
29
30     roles = ['admin', 'pi', 'tech', 'user']
31
32     lease_fields = dict(list(filter(can_update, list(Lease.fields.items()))))
33
34     accepts = [
35         Auth(),
36         Mixed(Lease.fields['lease_id'],
37               [Lease.fields['lease_id']]),
38         lease_fields
39     ]
40
41     returns = Parameter(
42         dict,
43         " 'updated_ids' is the list ids updated,"
44         "'errors' is a list of error strings")
45
46     debug = False
47 #    debug=True
48
49     def call(self, auth, lease_ids, input_fields):
50         input_fields = dict(list(filter(can_update, list(input_fields.items()))))
51
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'])
60
61         # Get lease information
62         leases = Leases(self.api, lease_ids)
63         if not leases:
64             raise PLCInvalidArgument("No such leases {}".format(lease_ids))
65
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])
72
73         updated_ids = []
74         errors = []
75
76         lease_ids = [lease['lease_id'] for lease in leases]
77         for lease in leases:
78
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']))
92
93             try:
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
98                 else:
99                     # all arithmetics on longs..
100                     duration = Duration.validate(input_fields['duration'])
101                     # specify 'duration':0 to keep duration unchanged
102                     if not duration:
103                         duration = Timestamp.cast_long(
104                                        lease['t_until']) \
105                                  - Timestamp.cast_long(lease['t_from'])
106                     if 't_from' in input_fields:
107                         lease_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:
112                         lease_fields = {
113                             't_from': Timestamp.cast_long(
114                                           input_fields['t_until']) - duration,
115                             't_until': input_fields['t_until']}
116                     else:
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(
123                                 lease_fields[k]))
124
125                 lease.update(lease_fields)
126                 lease.sync()
127                 updated_ids.append(lease['lease_id'])
128             except Exception as e:
129                 errors.append(
130                     "Could not update lease {} - check new time limits ? -- {}"
131                     .format(lease['lease_id'], e))
132
133         # Logging variables
134         self.event_objects = {'Lease': updated_ids}
135         self.message = 'lease {} updated: {}'\
136                        .format(lease_ids, ", ".join(list(input_fields.keys())))
137
138         return {'updated_ids': updated_ids,
139                 'errors': errors}