add new slice functions
[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 PasswordAuth
8 from PLC.Sites import Site, Sites
9
10 class UpdateSlice(Method):
11     """
12     Updates the parameters of an existing slice with the values in
13     update_fields.
14
15     Users may only update slices of which they are members. PIs may
16     update any of the slices at their slices. Admins may update any
17     slice.
18
19     Only PIs and admins may update max_nodes. Slices cannot be renewed
20     (by updating the expires parameter) more than 8 weeks into the
21     future.
22
23     Returns 1 if successful, faults otherwise.
24     """
25
26     roles = ['admin', 'pi', 'user']
27
28     can_update = lambda (field, value): field in \
29                  ['instantiation', 'url', 'description', 'max_nodes', 'expires']
30     update_fields = dict(filter(can_update, Slice.fields.items()))
31
32     accepts = [
33         PasswordAuth(),
34         Mixed(Slice.fields['slice_id'],
35               Slice.fields['name']),
36         update_fields
37         ]
38
39     returns = Parameter(int, '1 if successful')
40
41     def call(self, auth, slice_id_or_name, update_fields):
42         if filter(lambda field: field not in self.update_fields, update_fields):
43             raise PLCInvalidArgument, "Invalid field specified"
44
45         slices = Slices(self.api, [slice_id_or_name]).values()
46         if not slices:
47             raise PLCInvalidArgument, "No such slice"
48         slice = slices[0]
49
50         if 'admin' not in self.caller['roles']:
51             if self.caller['person_id'] in slice['person_ids']:
52                 pass
53             elif 'pi' not in self.caller['roles']:
54                 raise PLCPermissionDenied, "Not a member of the specified slice"
55             elif slice['site_id'] not in self.caller['site_ids']:
56                 raise PLCPermissionDenied, "Specified slice not associated with any of your sites"
57
58         # Renewing
59         if 'expires' in update_fields and update_fields['expires'] > slice['expires']:
60             sites = Sites(self.api, [slice['site_id']]).values()
61             assert sites
62             site = sites[0]
63
64             if site['max_slices'] < 0:
65                 raise PLCInvalidArgument, "Slice creation and renewal have been disabled for the site"
66
67             # Maximum expiration date is 8 weeks from now
68             # XXX Make this configurable
69             max_expires = time.time() + (8 * 7 * 24 * 60 * 60)
70
71             if 'admin' not in self.caller['roles'] and update_fields['expires'] > max_expires:
72                 raise PLCInvalidArgument, "Cannot renew a slice beyond 8 weeks from now"
73
74         if 'max_nodes' in update_fields and update_fields['max_nodes'] != slice['max_nodes']:
75             if 'admin' not in self.caller['roles'] and \
76                'pi' not in self.caller['roles']:
77                 raise PLCInvalidArgument, "Only admins and PIs may update max_nodes"
78
79         slice.update(update_fields)
80
81         # XXX Make this a configurable policy
82         if slice['description'] is None or not slice['description'].strip() or \
83            slice['url'] is None or not slice['url'].strip():
84             raise PLCInvalidArgument, "Cannot renew a slice with an empty description or URL"
85
86         slice.sync()
87
88         return 1