added sfa upcalls
[plcapi.git] / PLC / Methods / AddSlice.py
1 # $Id$
2 # $URL$
3 import re
4
5 from PLC.Faults import *
6 from PLC.Auth import Auth
7 from PLC.Method import Method
8 from PLC.Parameter import Parameter, Mixed
9 from PLC.Table import Row
10
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
17 from PLC.SFA import SFA
18
19 can_update = ['name', 'instantiation', 'url', 'description', 'max_nodes']
20
21 class AddSlice(Method):
22     """
23     Adds a new slice. Any fields specified in slice_fields are used,
24     otherwise defaults are used.
25
26     Valid slice names are lowercase and begin with the login_base
27     (slice prefix) of a valid site, followed by a single
28     underscore. Thereafter, only letters, numbers, or additional
29     underscores may be used.
30
31     PIs may only add slices associated with their own sites (i.e.,
32     slice prefixes must always be the login_base of one of their
33     sites).
34
35     Returns the new slice_id (> 0) if successful, faults otherwise.
36     """
37
38     roles = ['admin', 'pi']
39
40     accepted_fields = Row.accepted_fields(can_update, Slice.fields)
41     accepted_fields.update(Slice.tags)
42
43     accepts = [
44         Auth(),
45         accepted_fields
46         ]
47
48     returns = Parameter(int, 'New slice_id (> 0) if successful')
49
50     def call(self, auth, slice_fields):
51
52         [native,tags,rejected]=Row.split_fields(slice_fields,[Slice.fields,Slice.tags])
53
54         # type checking
55         native = Row.check_fields (native, self.accepted_fields)
56         if rejected:
57             raise PLCInvalidArgument, "Cannot add Slice with column(s) %r"%rejected
58
59         # Authenticated function
60         assert self.caller is not None
61
62         # 1. Lowercase.
63         # 2. Begins with login_base (letters or numbers).
64         # 3. Then single underscore after login_base.
65         # 4. Then letters, numbers, or underscores.
66         name = slice_fields['name']
67         good_name = r'^[a-z0-9]+_[a-zA-Z0-9_]+$'
68         if not name or \
69            not re.match(good_name, name):
70             raise PLCInvalidArgument, "Invalid slice name"
71
72         # Get associated site details
73         login_base = name.split("_")[0]
74         sites = Sites(self.api, [login_base])
75         if not sites:
76             raise PLCInvalidArgument, "Invalid slice prefix %s in %s"%(login_base,name)
77         site = sites[0]
78
79         if 'admin' not in self.caller['roles']:
80             if site['site_id'] not in self.caller['site_ids']:
81                 raise PLCPermissionDenied, "Slice prefix %s must match one of your sites' login_base"%login_base
82
83         if len(site['slice_ids']) >= site['max_slices']:
84             raise PLCInvalidArgument, \
85                 "Site %s has reached (%d) its maximum allowable slice count (%d)"%(site['name'],
86                                                                                    len(site['slice_ids']),
87                                                                                    site['max_slices'])
88         if not site['enabled']:
89             raise PLCInvalidArgument, "Site %s is disabled and can cannot create slices" % (site['name'])
90          
91         slice = Slice(self.api, native)
92         slice['creator_person_id'] = self.caller['person_id']
93         slice['site_id'] = site['site_id']
94         slice.sync()
95
96         for (tagname,value) in tags.iteritems():
97             # the tagtype instance is assumed to exist, just check that
98             if not TagTypes(self.api,{'tagname':tagname}):
99                 raise PLCInvalidArgument,"No such TagType %s"%tagname
100             slice_tags=SliceTags(self.api,{'tagname':tagname,'slice_id':slice['slice_id']})
101             if not slice_tags:
102                 AddSliceTag(self.api).__call__(auth,slice['slice_id'],tagname,value)
103             else:
104                 UpdateSliceTag(self.api).__call__(auth,slice_tags[0]['slice_tag_id'],value)
105
106         self.event_objects = {'Slice': [slice['slice_id']]}
107         self.message = "Slice %d created" % slice['slice_id']
108     
109         sfa = SFA()
110         sfa.update_record(slice, 'slice', site['login_base']) 
111         return slice['slice_id']