5 from PLC.Faults import *
6 from PLC.Method import Method
7 from PLC.Parameter import Parameter, Mixed
8 from PLC.Table import Row
9 from PLC.Auth import Auth
11 from PLC.Slices import Slice, Slices
12 from PLC.Sites import Site, Sites
13 from PLC.TagTypes import TagTypes
14 from PLC.SliceTags import SliceTags
15 from PLC.Methods.AddSliceTag import AddSliceTag
16 from PLC.Methods.UpdateSliceTag import UpdateSliceTag
18 can_update = ['instantiation', 'url', 'description', 'max_nodes', 'expires']
20 class UpdateSlice(Method):
22 Updates the parameters of an existing slice with the values in
25 Users may only update slices of which they are members. PIs may
26 update any of the slices at their sites, or any slices of which
27 they are members. Admins may update any slice.
29 Only PIs and admins may update max_nodes. Slices cannot be renewed
30 (by updating the expires parameter) more than 8 weeks into the
33 Returns 1 if successful, faults otherwise.
36 roles = ['admin', 'pi', 'user']
38 accepted_fields = Row.accepted_fields(can_update, Slice.fields)
39 # xxx check the related_fields feature
40 accepted_fields.update(Slice.related_fields)
41 accepted_fields.update(Slice.tags)
45 Mixed(Slice.fields['slice_id'],
46 Slice.fields['name']),
50 returns = Parameter(int, '1 if successful')
52 def call(self, auth, slice_id_or_name, slice_fields):
54 # split provided fields
55 [native,related,tags,rejected] = Row.split_fields(slice_fields,[Slice.fields,Slice.related_fields,Slice.tags])
58 native = Row.check_fields (native, self.accepted_fields)
60 raise PLCInvalidArgument, "Cannot update Slice column(s) %r"%rejected
62 slices = Slices(self.api, [slice_id_or_name])
64 raise PLCInvalidArgument, "No such slice %r"%slice_id_or_name
67 if slice['peer_id'] is not None:
68 raise PLCInvalidArgument, "Not a local slice"
70 # Authenticated function
71 assert self.caller is not None
73 if 'admin' not in self.caller['roles']:
74 if self.caller['person_id'] in slice['person_ids']:
76 elif 'pi' not in self.caller['roles']:
77 raise PLCPermissionDenied, "Not a member of the specified slice"
78 elif slice['site_id'] not in self.caller['site_ids']:
79 raise PLCPermissionDenied, "Specified slice not associated with any of your sites"
83 if 'expires' in slice_fields and slice_fields['expires'] > slice['expires']:
84 sites = Sites(self.api, [slice['site_id']])
88 if site['max_slices'] <= 0:
89 raise PLCInvalidArgument, "Slice creation and renewal have been disabled for the site"
91 # Maximum expiration date is 8 weeks from now
92 # XXX Make this configurable
93 max_expires = time.time() + (8 * 7 * 24 * 60 * 60)
95 if 'admin' not in self.caller['roles'] and slice_fields['expires'] > max_expires:
96 raise PLCInvalidArgument, "Cannot renew a slice beyond 8 weeks from now"
98 # XXX Make this a configurable policy
99 if slice['description'] is None or not slice['description'].strip():
100 if 'description' not in slice_fields or slice_fields['description'] is None or \
101 not slice_fields['description'].strip():
102 raise PLCInvalidArgument, "Cannot renew a slice with an empty description or URL"
104 if slice['url'] is None or not slice['url'].strip():
105 if 'url' not in slice_fields or slice_fields['url'] is None or \
106 not slice_fields['url'].strip():
107 raise PLCInvalidArgument, "Cannot renew a slice with an empty description or URL"
110 if 'max_nodes' in slice_fields and slice_fields['max_nodes'] != slice['max_nodes']:
111 if 'admin' not in self.caller['roles'] and \
112 'pi' not in self.caller['roles']:
113 raise PLCInvalidArgument, "Only admins and PIs may update max_nodes"
115 # Make requested associations
116 for (k,v) in related.iteritems():
117 slice.associate(auth,k,v)
119 slice.update(slice_fields)
120 slice.sync(commit=True)
122 for (tagname,value) in tags.iteritems():
123 # the tagtype instance is assumed to exist, just check that
124 if not TagTypes(self.api,{'tagname':tagname}):
125 raise PLCInvalidArgument,"No such TagType %s"%tagname
126 slice_tags=SliceTags(self.api,{'tagname':tagname,'slice_id':slice['slice_id']})
128 AddSliceTag(self.api).__call__(auth,slice['slice_id'],tagname,value)
130 UpdateSliceTag(self.api).__call__(auth,slice_tags[0]['slice_tag_id'],value)
132 self.event_objects = {'Slice': [slice['slice_id']]}
134 self.message='Slice %s updated'%slice['name']
136 self.message='Slice %d updated'%slice['slice_id']
138 # it appears that slice['expires'] may be either an int, or a formatted string
140 expire_date=time.strftime('%Y-%m-%d:%H:%M',time.localtime(float(slice['expires'])))
142 expire_date=slice['expires']
143 self.message += ' renewed until %s'%expire_date