-fix bug: users can properly update slice description/url if slice has none
[plcapi.git] / PLC / Methods / UpdateSlice.py
1 import time
2
3 from PLC.Faults import *
4 from PLC.Method import Method
5 from PLC.Parameter import Parameter, Mixed
6 from PLC.Slices import Slice, Slices
7 from PLC.Auth import Auth
8 from PLC.Sites import Site, Sites
9
10 related_fields = Slice.related_fields.keys() 
11 can_update = lambda (field, value): field in \
12              ['instantiation', 'url', 'description', 'max_nodes', 'expires'] + \
13              related_fields
14
15
16 class UpdateSlice(Method):
17     """
18     Updates the parameters of an existing slice with the values in
19     slice_fields.
20
21     Users may only update slices of which they are members. PIs may
22     update any of the slices at their sites, or any slices of which
23     they are members. Admins may update any slice.
24
25     Only PIs and admins may update max_nodes. Slices cannot be renewed
26     (by updating the expires parameter) more than 8 weeks into the
27     future.
28
29     Returns 1 if successful, faults otherwise.
30     """
31
32     roles = ['admin', 'pi', 'user']
33
34     slice_fields = dict(filter(can_update, Slice.fields.items() + Slice.related_fields.items()))
35
36     accepts = [
37         Auth(),
38         Mixed(Slice.fields['slice_id'],
39               Slice.fields['name']),
40         slice_fields
41         ]
42
43     returns = Parameter(int, '1 if successful')
44
45     def call(self, auth, slice_id_or_name, slice_fields):
46         slice_fields = dict(filter(can_update, slice_fields.items()))
47         
48         slices = Slices(self.api, [slice_id_or_name])
49         if not slices:
50             raise PLCInvalidArgument, "No such slice"
51         slice = slices[0]
52
53         if slice['peer_id'] is not None:
54             raise PLCInvalidArgument, "Not a local slice"
55
56         if 'admin' not in self.caller['roles']:
57             if self.caller['person_id'] in slice['person_ids']:
58                 pass
59             elif 'pi' not in self.caller['roles']:
60                 raise PLCPermissionDenied, "Not a member of the specified slice"
61             elif slice['site_id'] not in self.caller['site_ids']:
62                 raise PLCPermissionDenied, "Specified slice not associated with any of your sites"
63
64         # Renewing
65         if 'expires' in slice_fields and slice_fields['expires'] > slice['expires']:
66             sites = Sites(self.api, [slice['site_id']])
67             assert sites
68             site = sites[0]
69
70             if site['max_slices'] < 0:
71                 raise PLCInvalidArgument, "Slice creation and renewal have been disabled for the site"
72
73             # Maximum expiration date is 8 weeks from now
74             # XXX Make this configurable
75             max_expires = time.time() + (8 * 7 * 24 * 60 * 60)
76
77             if 'admin' not in self.caller['roles'] and slice_fields['expires'] > max_expires:
78                 raise PLCInvalidArgument, "Cannot renew a slice beyond 8 weeks from now"
79
80             # XXX Make this a configurable policy
81             if slice['description'] is None or not slice['description'].strip():
82                 if 'description' not in slice_fields or slice_fields['description'] is None or \
83                    not slice_fields['description'].strip():
84                      raise PLCInvalidArgument, "Cannot renew a slice with an empty description or URL"  
85                
86             if slice['url'] is None or not slice['url'].strip():
87                 if 'url' not in slice_fields or slice_fields['url'] is None or \
88                    not slice_fields['url'].strip():
89                     raise PLCInvalidArgument, "Cannot renew a slice with an empty description or URL"
90             
91         if 'max_nodes' in slice_fields and slice_fields['max_nodes'] != slice['max_nodes']:
92             if 'admin' not in self.caller['roles'] and \
93                'pi' not in self.caller['roles']:
94                 raise PLCInvalidArgument, "Only admins and PIs may update max_nodes"
95
96         # Make requested associations
97         for field in related_fields:
98             if field in slice_fields:
99                 slice.associate(auth, field, slice_fields[field])
100                 slice_fields.pop(field)
101
102         slice.update(slice_fields)
103         slice.sync()
104
105         self.event_objects = {'Slice': [slice['slice_id']]}
106
107         return 1