4 from PLC.Faults import *
5 from PLC.Method import Method
6 from PLC.Parameter import Parameter, Mixed
7 from PLC.Table import Row
8 from PLC.Auth import Auth
10 from PLC.Slices import Slice, Slices
11 from PLC.Sites import Site, Sites
12 from PLC.TagTypes import TagTypes
13 from PLC.SliceTags import SliceTags
14 from PLC.Methods.AddSliceTag import AddSliceTag
15 from PLC.Methods.UpdateSliceTag import UpdateSliceTag
17 can_update = ['instantiation', 'url', 'description', 'max_nodes', 'expires'] + \
18 Slice.related_fields.keys()
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 slice_fields = Row.accepted_fields(can_update, [Slice.fields,Slice.related_fields,Slice.tags])
42 Mixed(Slice.fields['slice_id'],
43 Slice.fields['name']),
47 returns = Parameter(int, '1 if successful')
49 def call(self, auth, slice_id_or_name, slice_fields):
51 # split provided fields
52 [native,related,tags,rejected] = Row.split_fields(slice_fields,[Slice.fields,Slice.related_fields,Slice.tags])
55 raise PLCInvalidArgument, "Cannot update Slice column(s) %r"%rejected
57 slices = Slices(self.api, [slice_id_or_name])
59 raise PLCInvalidArgument, "No such slice %r"%slice_id_or_name
62 if slice['peer_id'] is not None:
63 raise PLCInvalidArgument, "Not a local slice"
65 # Authenticated function
66 assert self.caller is not None
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, "Not a member of the specified slice"
73 elif slice['site_id'] not in self.caller['site_ids']:
74 raise PLCPermissionDenied, "Specified slice not associated with any of your sites"
78 if 'expires' in slice_fields and slice_fields['expires'] > slice['expires']:
79 sites = Sites(self.api, [slice['site_id']])
83 if site['max_slices'] <= 0:
84 raise PLCInvalidArgument, "Slice creation and renewal have been disabled for the site"
86 # Maximum expiration date is 8 weeks from now
87 # XXX Make this configurable
88 max_expires = time.time() + (8 * 7 * 24 * 60 * 60)
90 if 'admin' not in self.caller['roles'] and slice_fields['expires'] > max_expires:
91 raise PLCInvalidArgument, "Cannot renew a slice beyond 8 weeks from now"
93 # XXX Make this a configurable policy
94 if slice['description'] is None or not slice['description'].strip():
95 if 'description' not in slice_fields or slice_fields['description'] is None or \
96 not slice_fields['description'].strip():
97 raise PLCInvalidArgument, "Cannot renew a slice with an empty description or URL"
99 if slice['url'] is None or not slice['url'].strip():
100 if 'url' not in slice_fields or slice_fields['url'] is None or \
101 not slice_fields['url'].strip():
102 raise PLCInvalidArgument, "Cannot renew a slice with an empty description or URL"
105 if 'max_nodes' in slice_fields and slice_fields['max_nodes'] != slice['max_nodes']:
106 if 'admin' not in self.caller['roles'] and \
107 'pi' not in self.caller['roles']:
108 raise PLCInvalidArgument, "Only admins and PIs may update max_nodes"
110 # Make requested associations
111 for (k,v) in related.iteritems():
112 slice.associate(auth,k,v)
114 slice.update(slice_fields)
115 slice.sync(commit=True)
117 for (tagname,value) in tags.iteritems():
118 # the tagtype instance is assumed to exist, just check that
119 if not TagTypes(self.api,{'tagname':tagname}):
120 raise PLCInvalidArgument,"No such TagType %s"%tagname
121 slice_tags=SliceTags(self.api,{'tagname':tagname,'slice_id':slice['slice_id']})
123 AddSliceTag(self.api).__call__(auth,slice['slice_id'],tagname,value)
125 UpdateSliceTag(self.api).__call__(auth,slice_tags[0]['slice_tag_id'],value)
127 self.event_objects = {'Slice': [slice['slice_id']]}
129 self.message='Slice %s updated'%slice['name']
131 self.message='Slice %d updated'%slice['slice_id']
133 # it appears that slice['expires'] may be either an int, or a formatted string
135 expire_date=time.strftime('%Y-%m-%d:%H:%M',time.localtime(float(slice['expires'])))
137 expire_date=slice['expires']
138 self.message += ' renewed until %s'%expire_date