1 # Thierry Parmentelat -- INRIA
3 from PLC.Faults import *
4 from PLC.Auth import Auth
5 from PLC.Method import Method
6 from PLC.Parameter import Parameter, Mixed
7 from PLC.Table import Row
9 from PLC.Leases import Leases, Lease
10 from PLC.Nodes import Nodes, Node
11 from PLC.Slices import Slices, Slice
12 from PLC.Timestamp import Timestamp
14 can_update = ['name', 'instantiation', 'url', 'description', 'max_nodes']
17 class AddLeases(Method):
20 Mandatory arguments are node(s), slice, t_from and t_until
21 times can be either integers, datetime's, or human readable (see Timestamp)
23 PIs may only add leases associated with their own sites (i.e.,
24 to a slice that belongs to their site).
25 Users may only add leases associated with their own slices.
27 Returns the new lease_ids if successful, faults otherwise.
30 roles = ['admin', 'pi', 'user']
34 Mixed(Node.fields['node_id'], [Node.fields['node_id']],
35 Node.fields['hostname'], [Node.fields['hostname']],),
36 Mixed(Slice.fields['slice_id'],
37 Slice.fields['name']),
38 Mixed(Lease.fields['t_from']),
39 Mixed(Lease.fields['t_until']),
44 " 'new_ids' is the list of newly created ids,"
45 "'errors' is a list of error strings")
47 def call(self, auth, node_id_or_hostname_s, slice_id_or_name,
50 # Get node information
51 nodes = Nodes(self.api, node_id_or_hostname_s)
53 raise PLCInvalidArgument(
54 "No such node(s) {}".format(node_id_or_hostname_s))
56 if node['node_type'] != 'reservable':
57 raise PLCInvalidArgument(
58 "Node {} is not reservable".format(node['hostname']))
60 # Get slice information
61 slices = Slices(self.api, [slice_id_or_name])
63 raise PLCInvalidArgument(
64 "No such slice {}".format(slice_id_or_name))
68 if 'admin' not in self.caller['roles']:
69 if self.caller['person_id'] in slice['person_ids']:
71 elif 'pi' not in self.caller['roles']:
72 raise PLCPermissionDenied(
73 "Not a member of the specified slice")
74 elif slice['site_id'] not in self.caller['site_ids']:
75 raise PLCPermissionDenied(
76 "Specified slice not associated with any of your sites")
78 # normalize timestamps - use granularity to round up limits
79 t_from = Timestamp.sql_validate_utc(t_from)
80 t_until = Timestamp.sql_validate_utc(t_until)
86 if node['peer_id'] is not None:
87 errors.append("Cannot set lease on remote node {}"
88 .format(node['hostname']))
90 # let the DB check for time consistency
92 lease = Lease(self.api, {'node_id': node['node_id'],
93 'slice_id': slice['slice_id'],
94 't_from': t_from, 't_until': t_until})
96 result_ids.append(lease['lease_id'])
98 except PLCDBError as e:
100 "Timeslot busy - could not create overlapping lease"
101 " on n={} s={} [{} .. {}]"
102 .format(node['hostname'], slice['name'], t_from, t_until))
104 except Exception as e:
106 "Could not create lease on n={} s={} [{} .. {}] -- {}"
107 .format(node['hostname'], slice['name'], t_from, t_until, e))
110 self.event_objects = {'Slice': [slice['slice_id']],
111 'Node': [node['node_id'] for node in nodes]}
112 self.message = "New leases {} on n={} s={} [{} -> {}]"\
113 .format(result_ids, [node['hostname'] for node in nodes],
114 slice['name'], t_from, t_until)
116 return {'new_ids': result_ids, 'errors': errors}