3 from PLC.Faults import *
4 from PLC.Auth import Auth
5 from PLC.Method import Method
6 from PLC.Parameter import Parameter, Mixed
7 from PLC.Table import Row
9 from PLC.Slices import Slice, Slices
10 from PLC.Sites import Site, Sites
11 from PLC.TagTypes import TagTypes
12 from PLC.SliceTags import SliceTags
13 from PLC.Methods.AddSliceTag import AddSliceTag
14 from PLC.Methods.UpdateSliceTag import UpdateSliceTag
16 can_update = ['name', 'instantiation', 'url', 'description', 'max_nodes']
18 # it would be much better to have this configured from the outside
19 # this is not, however, the subject of the current exercise
20 # so let's keep it simple for now
21 VLAN_RANGE = range(128,255) # this would be 128 .. 254 inclusively
23 # also this would require the following code added in your Accessors_site.py
24 #define_accessors(current_module, Slice, 'VlanId', 'vlan_id',
25 # "slice/general", "the vlan_id allocated to that slice",
26 # get_roles=all_roles, set_roles=admin_roles)
27 # see https://svn.planet-lab.org/wiki/TagsAndAccessors for more details
29 class AddSlice(Method):
31 Adds a new slice. Any fields specified in slice_fields are used,
32 otherwise defaults are used.
34 Valid slice names are lowercase and begin with the login_base
35 (slice prefix) of a valid site, followed by a single
36 underscore. Thereafter, only letters, numbers, or additional
37 underscores may be used.
39 PIs may only add slices associated with their own sites (i.e.,
40 slice prefixes must always be the login_base of one of their
43 Returns the new slice_id (> 0) if successful, faults otherwise.
46 roles = ['admin', 'pi']
48 accepted_fields = Row.accepted_fields(can_update, Slice.fields)
49 accepted_fields.update(Slice.tags)
56 returns = Parameter(int, 'New slice_id (> 0) if successful')
58 def call(self, auth, slice_fields):
60 [native,tags,rejected]=Row.split_fields(slice_fields,[Slice.fields,Slice.tags])
63 native = Row.check_fields (native, self.accepted_fields)
65 raise PLCInvalidArgument, "Cannot add Slice with column(s) %r"%rejected
67 # Authenticated function
68 assert self.caller is not None
71 # 2. Begins with login_base (letters or numbers).
72 # 3. Then single underscore after login_base.
73 # 4. Then letters, numbers, or underscores.
74 name = slice_fields['name']
75 good_name = r'^[a-z0-9]+_[a-zA-Z0-9_]+$'
77 not re.match(good_name, name):
78 raise PLCInvalidArgument, "Invalid slice name"
80 # Get associated site details
81 login_base = name.split("_")[0]
82 sites = Sites(self.api, [login_base])
84 raise PLCInvalidArgument, "Invalid slice prefix %s in %s"%(login_base,name)
87 #################### provisioning vlan_ids
88 # retrieve all alive slices
89 alive_slices=Slices(self.api,{},['slice_id','name','slice_tag_ids'])
90 # build the list of their ids
91 alive_slices_ids = [ s['slice_id'] for s in alive_slices ]
92 # retrieve all the 'vlan_id' slice tags applying to these slice_ids
93 vlan_slice_tags = SliceTags (self.api,{'slice_id':alive_slices_ids,'tagname':'vlan_id'})
94 # hash them by the slice_tag_id
95 vlan_slice_tags_hashed_by_id = { slice_tag['slice_tag_id']:slice_tag for slice_tag in vlan_slice_tags }
96 # build the set of allocated vlans
97 allocated_vlan_ids = set()
98 for alive_slice in alive_slices:
99 # scan all slice tags attached to that slice
100 for slice_tag_id in alive_slice['slice_tag_ids']:
101 # discard the one that are not 'vlan_id'
102 if slice_tag_id not in vlan_slice_tags_hashed_by_id: continue
103 # retrive value and convert to int
104 slice_tag = vlan_slice_tags_hashed_by_id[slice_tag_id]
105 if slice_tag['tagname']=='vlan_id':
107 allocated_vlan_ids.add(int(slice_tag['value']))
110 traceback.print_exc()
112 # find a free vlan_id
113 available=set(VLAN_RANGE) - allocated_vlan_ids
115 assigned=available.pop()
116 # piggybacking the code below that sets tags; tags value need to be strings..
117 tags['vlan_id']=str(assigned)
119 raise Exception,"Cannot allocate slice %s, ran out of vlan_ids"%name
121 if 'admin' not in self.caller['roles']:
122 if site['site_id'] not in self.caller['site_ids']:
123 raise PLCPermissionDenied, "Slice prefix %s must match one of your sites' login_base"%login_base
125 if len(site['slice_ids']) >= site['max_slices']:
126 raise PLCInvalidArgument, \
127 "Site %s has reached (%d) its maximum allowable slice count (%d)"%(site['name'],
128 len(site['slice_ids']),
130 if not site['enabled']:
131 raise PLCInvalidArgument, "Site %s is disabled and can cannot create slices" % (site['name'])
133 slice = Slice(self.api, native)
134 slice['creator_person_id'] = self.caller['person_id']
135 slice['site_id'] = site['site_id']
139 root_auth = self.api.config.PLC_HRN_ROOT
140 tags['hrn'] = '.'.join([root_auth, login_base, name.split("_")[1]])
142 for (tagname,value) in tags.iteritems():
143 # the tagtype instance is assumed to exist, just check that
144 if not TagTypes(self.api,{'tagname':tagname}):
145 raise PLCInvalidArgument,"No such TagType %s"%tagname
146 slice_tags=SliceTags(self.api,{'tagname':tagname,'slice_id':slice['slice_id']})
148 AddSliceTag(self.api).__call__(auth,slice['slice_id'],tagname,value)
150 UpdateSliceTag(self.api).__call__(auth,slice_tags[0]['slice_tag_id'],value)
152 # take PLC_VSYS_DEFAULTS into account for convenience
154 values= [ y for y in [ x.strip() for x in self.api.config.PLC_VSYS_DEFAULTS.split(',') ] if y ]
156 AddSliceTag(self.api).__call__(auth,slice['slice_id'],'vsys',value)
158 print "Could not set vsys tags as configured in PLC_VSYS_DEFAULTS"
160 traceback.print_exc()
161 self.event_objects = {'Slice': [slice['slice_id']]}
162 self.message = "Slice %d created" % slice['slice_id']
164 return slice['slice_id']