blob: babaa7c6a0863df468e66dc43e79c3fad2158996 [file] [log] [blame]
Nikolay Titov89004ec2017-06-19 18:22:42 -04001# Copyright 2017 the original author or authors.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14#
15from Queue import Empty as QueueEmpty
16
17import structlog
18import re
19from uuid import uuid4
20
21from google.protobuf.empty_pb2 import Empty
22from grpc import StatusCode
23
24from voltha.protos.bbf_fiber_base_pb2 import \
25 AllChannelgroupConfig, ChannelgroupConfig, \
26 AllChannelpairConfig, ChannelpairConfig, \
27 AllChannelpartitionConfig, ChannelpartitionConfig, \
28 AllChannelterminationConfig, ChannelterminationConfig, \
29 AllOntaniConfig, OntaniConfig, AllVOntaniConfig , VOntaniConfig, \
Nikolay Titov176f1db2017-08-10 12:38:43 -040030 AllVEnetConfig, VEnetConfig, AllTrafficDescriptorProfileData, \
31 AllTcontsConfigData, AllGemportsConfigData
32from voltha.protos.bbf_fiber_traffic_descriptor_profile_body_pb2 import \
33 TrafficDescriptorProfileData
34from voltha.protos.bbf_fiber_tcont_body_pb2 import TcontsConfigData
35from voltha.protos.bbf_fiber_gemport_body_pb2 import GemportsConfigData
Nikolay Titov89004ec2017-06-19 18:22:42 -040036
37from voltha.protos.device_pb2 import Device
38from voltha.protos.common_pb2 import AdminState
39
Rachit Shrivastava8e435b42017-08-08 23:15:26 -040040from common.utils.indexpool import IndexPool
41
Nikolay Titov89004ec2017-06-19 18:22:42 -040042from requests.api import request
43
44log = structlog.get_logger()
45
46
47class XponHandler(object):
48 def __init__(self, core):
49 self.core = core
50 self.root = None
Rachit Shrivastava8e435b42017-08-08 23:15:26 -040051 '''
52 Pool for handling channel group indices
53 @TODO: As per current persistency & HA design, each VOLTHA instance
54 maintains a separate independent database. Since channel-groups are
55 broadcast to all the VOLTHA instances in the cluster, the
56 xpon_handler in each instance will independently try to allocate a
57 unique index. This approach works OK for XGS-PON since CG<->CTerm
58 relationship is 1:1 for XGS-PON(Since a device can only be served
59 by one VOLTHA instance and thereby CTerm). This needs to be further
60 investigated wrt persistency & HA design evolution, for a better
61 approach in future.
62 '''
Niren R Chidrawar11e4d7c2017-08-17 23:21:31 -040063 self.cg_pool = IndexPool(2**11-1, 1)
Nikolay Titov7253ff22017-08-14 18:24:17 -040064 self.cg_dict = {}
Nikolay Titov89004ec2017-06-19 18:22:42 -040065
66 def start(self, root):
67 log.debug('starting xpon_handler')
68 self.root = root
Nikolay Titov7253ff22017-08-14 18:24:17 -040069 self.reinitialize_cg_ids()
70 self.reinitialize_tcont_and_gemport_ids()
71
72 def reinitialize_cg_ids(self):
73 cg_tup = ()
74 channel_groups = self.root.get('/channel_groups')
75 for cg in channel_groups:
76 cg_tup += (cg.cg_index, )
77 '''
78 Pools for handling alloc-ids and gemport-ids
79 @TODO: As per current persistency & HA design, each VOLTHA instance
80 maintains a separate independent database. Since channel-groups
81 broadcast to all the VOLTHA instances in the cluster, the
82 xpon_handler in each instance will independently try to
83 allocate a unique index. This approach works OK for XGS-PON
84 since CG<->CTerm relationship is 1:1 for XGS-PON(Since a device
85 can only be served by one VOLTHA instance and thereby CTerm).
86 This needs to be further investigated wrt persistency & HA
87 design evolution, for a better approach in future.
88 '''
89 self.cg_dict[cg.name] = {'alloc_id': IndexPool(16383, 1024)}
rshetty1cc73982017-09-02 03:31:12 +053090 self.cg_dict[cg.name].update({'gemport_id': IndexPool(64500, 1024)})
Nikolay Titov7253ff22017-08-14 18:24:17 -040091 self.cg_pool.pre_allocate(cg_tup)
92
93 def reinitialize_tcont_and_gemport_ids(self):
94 tconts = self.root.get('/tconts')
95 for tc in tconts:
96 cg_name = self.extract_channel_group_from_request(tc,
97 'v_ont_anis', tc.interface_reference)
98 self.cg_dict[cg_name]['alloc_id'].pre_allocate((tc.alloc_id, ))
99 gemports = self.root.get('/gemports')
100 for gm in gemports:
101 cg_name = self.extract_channel_group_from_request(gm,
102 'v_enets', gm.itf_ref)
103 self.cg_dict[cg_name]['gemport_id'].pre_allocate((gm.gemport_id, ))
Nikolay Titov89004ec2017-06-19 18:22:42 -0400104
105 def get_all_channel_group_config(self, request, context):
106 log.info('grpc-request', request=request)
107 items = self.root.get('/channel_groups')
108 return AllChannelgroupConfig(channelgroup_config=items)
109
Rachit Shrivastava8e435b42017-08-08 23:15:26 -0400110 def get_channel_group_config(self, request, context):
111 log.info('grpc-request', request=request)
112 item = self.root.get('/channel_groups/{}'.format(request.name))
113 if(isinstance(item, ChannelgroupConfig)):
114 return item
115 return Empty()
116
Nikolay Titov89004ec2017-06-19 18:22:42 -0400117 def create_channel_group(self, request, context):
118 log.info('grpc-request', request=request)
119
120 try:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400121 assert isinstance(request, ChannelgroupConfig), \
122 'Instance is not of Channel Group'
Nikolay Titov89004ec2017-06-19 18:22:42 -0400123 assert self.validate_interface(request, context)
124 log.debug('creating-channel-group', name=request.name)
Rachit Shrivastava8e435b42017-08-08 23:15:26 -0400125 _id = self.cg_pool.get_next()
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400126 assert _id != None, \
127 'Fail to allocate id for Channel Group'
Rachit Shrivastava8e435b42017-08-08 23:15:26 -0400128 request.cg_index = _id
Nikolay Titov89004ec2017-06-19 18:22:42 -0400129 self.root.add('/channel_groups', request)
Nikolay Titov7253ff22017-08-14 18:24:17 -0400130 self.cg_dict[request.name] = {'alloc_id': IndexPool(16383, 1024)}
rshetty1cc73982017-09-02 03:31:12 +0530131 self.cg_dict[request.name].update({'gemport_id': IndexPool(64500, 1024)})
Nikolay Titov89004ec2017-06-19 18:22:42 -0400132
133 return Empty()
134 except AssertionError, e:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400135 context.set_details(e.message)
Rachit Shrivastava8e435b42017-08-08 23:15:26 -0400136 context.set_code(StatusCode.INVALID_ARGUMENT)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400137 return Empty()
138 except ValueError:
Nikolay Titov7253ff22017-08-14 18:24:17 -0400139 self.cg_pool.release(_id)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400140 context.set_details(
Nikolay Titove44c3d22017-08-03 15:27:37 -0400141 'Duplicated channel group \'{}\' cannot be created'.format(
142 request.name))
Nikolay Titov89004ec2017-06-19 18:22:42 -0400143 context.set_code(StatusCode.INVALID_ARGUMENT)
144 return Empty()
145
146 def update_channel_group(self, request, context):
147 log.info('grpc-request', request=request)
148
149 if '/' in request.name:
150 context.set_details(
151 'Malformed name \'{}\''.format(request.name))
152 context.set_code(StatusCode.INVALID_ARGUMENT)
153 return ChannelgroupConfig()
154
155 try:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400156 assert isinstance(request, ChannelgroupConfig), \
157 'Instance is not of Channel Group'
Nikolay Titov89004ec2017-06-19 18:22:42 -0400158 assert self.validate_interface(request, context)
Rachit Shrivastava8e435b42017-08-08 23:15:26 -0400159 channelgroup = self.get_channel_group_config(request, context)
Rachit Shrivastava8e435b42017-08-08 23:15:26 -0400160 request.cg_index = channelgroup.cg_index
Nikolay Titov89004ec2017-06-19 18:22:42 -0400161 path = '/channel_groups/{}'.format(request.name)
162 log.debug('updating-channel-group', name=request.name)
163 self.root.update(path, request, strict=True)
164 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -0400165 except AssertionError, e:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400166 context.set_details(e.message)
167 context.set_code(StatusCode.INVALID_ARGUMENT)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400168 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -0400169 except KeyError:
170 context.set_details(
171 'channel group \'{}\' not found'.format(request.name))
172 context.set_code(StatusCode.NOT_FOUND)
173 return Empty()
174
175 def delete_channel_group(self, request, context):
176 log.info('grpc-request', request=request)
177
178 if '/' in request.name:
179 context.set_details(
180 'Malformed name \'{}\''.format(request.name))
181 context.set_code(StatusCode.INVALID_ARGUMENT)
182 return Empty()
183
184 try:
Nikolay Titov176f1db2017-08-10 12:38:43 -0400185 assert isinstance(request, ChannelgroupConfig), \
186 'Instance is not of Channel Group'
187 channelgroup_ref_by_channelpartition = next(
188 (cpart for cpart in self.root.get('/channel_partitions')
189 if cpart.data.channelgroup_ref == request.name), None)
190 assert channelgroup_ref_by_channelpartition is None, \
191 'Channel Group -- \'{}\' is referenced by Channel Partition'\
192 .format(request.name)
193 channelgroup_ref_by_channelpair = next(
194 (cpair for cpair in self.root.get('/channel_pairs')
195 if cpair.data.channelgroup_ref == request.name), None)
196 assert channelgroup_ref_by_channelpair is None, \
197 'Channel Group -- \'{}\' is referenced by Channel Pair'\
198 .format(request.name)
Rachit Shrivastava8e435b42017-08-08 23:15:26 -0400199 channelgroup = self.get_channel_group_config(request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400200 path = '/channel_groups/{}'.format(request.name)
201 log.debug('removing-channel-group', name=request.name)
202 self.root.remove(path)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400203 self.cg_pool.release(channelgroup.cg_index)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400204 return Empty()
Nikolay Titov176f1db2017-08-10 12:38:43 -0400205 except AssertionError, e:
206 context.set_details(e.message)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400207 context.set_code(StatusCode.INVALID_ARGUMENT)
208 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -0400209 except KeyError:
210 context.set_details(
211 'channel group \'{}\' not found'.format(request.name))
212 context.set_code(StatusCode.NOT_FOUND)
213 return Empty()
214
215 def get_all_channel_partition_config(self, request, context):
216 log.info('grpc-request', request=request)
217 items = self.root.get('/channel_partitions')
218 return AllChannelpartitionConfig(channelpartition_config=items)
219
220 def create_channel_partition(self, request, context):
221 log.info('grpc-request', request=request)
222
223 try:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400224 assert isinstance(request, ChannelpartitionConfig), \
225 'Instance is not of Channel Partition'
Nikolay Titov89004ec2017-06-19 18:22:42 -0400226 assert self.validate_interface(request, context)
227 log.debug('creating-channel-partition', name=request.name)
228 self.root.add('/channel_partitions', request)
229
230 return Empty()
231 except AssertionError, e:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400232 context.set_details(e.message)
233 context.set_code(StatusCode.INVALID_ARGUMENT)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400234 return Empty()
235 except ValueError:
236 context.set_details(
Nikolay Titove44c3d22017-08-03 15:27:37 -0400237 'Duplicated channel partition \'{}\' cannot be created'.format(
238 request.name))
Nikolay Titov89004ec2017-06-19 18:22:42 -0400239 context.set_code(StatusCode.INVALID_ARGUMENT)
240 return Empty()
241
242 def update_channel_partition(self, request, context):
243 log.info('grpc-request', request=request)
244
245 if '/' in request.name:
246 context.set_details(
247 'Malformed name \'{}\''.format(request.name))
248 context.set_code(StatusCode.INVALID_ARGUMENT)
249 return ChannelpartitionConfig()
250
251 try:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400252 assert isinstance(request, ChannelpartitionConfig), \
253 'Instance is not of Channel Partition'
Nikolay Titov89004ec2017-06-19 18:22:42 -0400254 assert self.validate_interface(request, context)
255
256 path = '/channel_partitions/{}'.format(request.name)
257 log.debug('updating-channel-partition', name=request.name)
258 self.root.update(path, request, strict=True)
259 return Empty()
260
261 except AssertionError, e:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400262 context.set_details(e.message)
263 context.set_code(StatusCode.INVALID_ARGUMENT)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400264 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -0400265 except KeyError:
266 context.set_details(
267 'channel partition \'{}\' not found'.format(request.name))
268 context.set_code(StatusCode.NOT_FOUND)
269 return Empty()
270
271 def delete_channel_partition(self, request, context):
272 log.info('grpc-request', request=request)
273
274 if '/' in request.name:
275 context.set_details(
276 'Malformed name \'{}\''.format(request.name))
277 context.set_code(StatusCode.INVALID_ARGUMENT)
278 return Empty()
279
280 try:
Nikolay Titov176f1db2017-08-10 12:38:43 -0400281 assert isinstance(request, ChannelpartitionConfig), \
282 'Instance is not of Channel Partition'
283 channelpartition_ref_by_channelpair = next(
284 (cpair for cpair in self.root.get('/channel_pairs')
285 if cpair.data.channelpartition_ref == request.name), None)
286 assert channelpartition_ref_by_channelpair is None, \
287 'Channel Partition -- \'{}\' is referenced by Channel Pair'\
288 .format(request.name)
289 channelpartition_ref_by_vontani = next(
290 (vont_ani for vont_ani in self.root.get('/v_ont_anis')
291 if vont_ani.data.parent_ref == request.name), None)
292 assert channelpartition_ref_by_vontani is None, \
293 'Channel Partition -- \'{}\' is referenced by VOntAni'\
294 .format(request.name)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400295 path = '/channel_partitions/{}'.format(request.name)
296 log.debug('removing-channel-partition', name=request.name)
297 self.root.remove(path)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400298 return Empty()
Nikolay Titov176f1db2017-08-10 12:38:43 -0400299 except AssertionError, e:
300 context.set_details(e.message)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400301 context.set_code(StatusCode.INVALID_ARGUMENT)
302 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -0400303 except KeyError:
304 context.set_details(
305 'channel partition \'{}\' not found'.format(request.name))
306 context.set_code(StatusCode.NOT_FOUND)
307 return Empty()
308
309 def get_all_channel_pair_config(self, request, context):
310 log.info('grpc-request', request=request)
311 items = self.root.get('/channel_pairs')
312 return AllChannelpairConfig(channelpair_config=items)
313
314 def create_channel_pair(self, request, context):
315 log.info('grpc-request', request=request)
316
317 try:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400318 assert isinstance(request, ChannelpairConfig), \
319 'Instance is not of Channel Pair'
Nikolay Titov89004ec2017-06-19 18:22:42 -0400320 assert self.validate_interface(request, context)
321 log.debug('creating-channel-pair', name=request.name)
322 self.root.add('/channel_pairs', request)
323
324 return Empty()
325 except AssertionError, e:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400326 context.set_details(e.message)
327 context.set_code(StatusCode.INVALID_ARGUMENT)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400328 return Empty()
329 except ValueError:
330 context.set_details(
Nikolay Titove44c3d22017-08-03 15:27:37 -0400331 'Duplicated channel pair \'{}\' cannot be created'.format(
332 request.name))
Nikolay Titov89004ec2017-06-19 18:22:42 -0400333 context.set_code(StatusCode.INVALID_ARGUMENT)
334 return Empty()
335
336 def update_channel_pair(self, request, context):
337 log.info('grpc-request', request=request)
338
339 if '/' in request.name:
340 context.set_details(
341 'Malformed name \'{}\''.format(request.name))
342 context.set_code(StatusCode.INVALID_ARGUMENT)
343 return ChannelpairConfig()
Nikolay Titov89004ec2017-06-19 18:22:42 -0400344 try:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400345 assert isinstance(request, ChannelpairConfig), \
346 'Instance is not of Channel Pair'
Nikolay Titov89004ec2017-06-19 18:22:42 -0400347 assert self.validate_interface(request, context)
348
349 path = '/channel_pairs/{}'.format(request.name)
350 log.debug('updating-channel-pair', name=request.name)
351 self.root.update(path, request, strict=True)
352 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -0400353 except AssertionError, e:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400354 context.set_details(e.message)
355 context.set_code(StatusCode.INVALID_ARGUMENT)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400356 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -0400357 except KeyError:
358 context.set_details(
359 'channel pair \'{}\' not found'.format(request.name))
360 context.set_code(StatusCode.NOT_FOUND)
361 return Empty()
362
363 def delete_channel_pair(self, request, context):
364 log.info('grpc-request', request=request)
365
366 if '/' in request.name:
367 context.set_details(
368 'Malformed name \'{}\''.format(request.name))
369 context.set_code(StatusCode.INVALID_ARGUMENT)
370 return Empty()
371
372 try:
Nikolay Titov176f1db2017-08-10 12:38:43 -0400373 assert isinstance(request, ChannelpairConfig), \
374 'Instance is not of Channel Pair'
Nikolay Titov89004ec2017-06-19 18:22:42 -0400375 device_items = self.root.get('/devices')
376 for device_item in device_items:
Nikolay Titov176f1db2017-08-10 12:38:43 -0400377 channelpair_ref_by_channeltermination = next(
378 (cterm for cterm in self.root.get(
Nikolay Titove44c3d22017-08-03 15:27:37 -0400379 '/devices/{}/channel_terminations'.format(
Nikolay Titov176f1db2017-08-10 12:38:43 -0400380 device_item.id))
381 if cterm.data.channelpair_ref == request.name), None)
382 assert channelpair_ref_by_channeltermination is None, \
383 'Channel Pair -- \'{}\' referenced by Channel Termination'\
384 .format(request.name)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400385 path = '/channel_pairs/{}'.format(request.name)
386 log.debug('removing-channel-pair', name=request.name)
387 self.root.remove(path)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400388 return Empty()
Nikolay Titov176f1db2017-08-10 12:38:43 -0400389 except AssertionError, e:
390 context.set_details(e.message)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400391 context.set_code(StatusCode.INVALID_ARGUMENT)
392 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -0400393 except KeyError:
394 context.set_details(
395 'channel pair \'{}\' not found'.format(request.name))
396 context.set_code(StatusCode.NOT_FOUND)
397 return Empty()
398
399 def get_all_channel_termination_config(self, request, context):
400 log.info('grpc-request', request=request)
401 if '/' in request.id:
402 context.set_details(
403 'Malformed device id \'{}\''.format(request.id))
404 context.set_code(StatusCode.INVALID_ARGUMENT)
405 return AllChannelterminationConfig()
406
407 try:
408 items = self.root.get(
409 '/devices/{}/channel_terminations'.format(request.id))
410 return AllChannelterminationConfig(channeltermination_config=items)
411 except KeyError:
412 context.set_details(
413 'Device \'{}\' not found'.format(request.id))
414 context.set_code(StatusCode.NOT_FOUND)
415 return AllChannelterminationConfig()
416
417 def create_channel_termination(self, request, context):
418 log.info('grpc-request', request=request)
419
420 try:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400421 assert isinstance(request, ChannelterminationConfig), \
422 'Instance is not of Channel Termination'
Nikolay Titov89004ec2017-06-19 18:22:42 -0400423 assert self.validate_interface(request, context)
424 #device = self.root.get('/devices/{}'.format(request.id))
425 except AssertionError, e:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400426 context.set_details(e.message)
427 context.set_code(StatusCode.INVALID_ARGUMENT)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400428 return Empty()
429 except KeyError:
430 context.set_details(
431 'Device \'{}\' not found'.format(request.id))
432 context.set_code(StatusCode.NOT_FOUND)
433 return Empty()
434 try:
435 path = '/devices/{}/channel_terminations'.format(request.id)
436 log.debug('creating-channel-termination', name=request.name)
437 self.root.add(path, request)
438 return Empty()
439 except KeyError:
440 context.set_details(
441 'Device \'{}\' not activated'.format(request.id))
442 context.set_code(StatusCode.NOT_FOUND)
443 return Empty()
444 except ValueError:
445 context.set_details(
Nikolay Titove44c3d22017-08-03 15:27:37 -0400446 'Duplicated channel termination \'{}\' cannot be created'.
447 format(request.name))
Nikolay Titov89004ec2017-06-19 18:22:42 -0400448 context.set_code(StatusCode.INVALID_ARGUMENT)
449 return Empty()
450
451 def update_channel_termination(self, request, context):
452 log.info('grpc-request', request=request)
453
454 if '/' in request.name:
455 context.set_details(
456 'Malformed name \'{}\''.format(request.name))
457 context.set_code(StatusCode.INVALID_ARGUMENT)
458 return ChannelterminationConfig()
459
460 try:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400461 assert isinstance(request, ChannelterminationConfig), \
462 'Instance is not of Channel Termination'
Nikolay Titov89004ec2017-06-19 18:22:42 -0400463 assert self.validate_interface(request, context)
464 except AssertionError, e:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400465 context.set_details(e.message)
466 context.set_code(StatusCode.INVALID_ARGUMENT)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400467 return Empty()
468 except KeyError:
469 context.set_details(
470 'Device \'{}\' not found'.format(request.id))
471 context.set_code(StatusCode.NOT_FOUND)
472 return Empty()
473
474 try:
Nikolay Titove44c3d22017-08-03 15:27:37 -0400475 path = '/devices/{}/channel_terminations/{}'.format(
476 request.id, request.name)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400477 log.debug('updating-channel-termination', name=request.name)
478 self.root.update(path, request, strict=True)
479 return Empty()
480
481 except KeyError:
482 context.set_details(
483 'channel termination \'{}\' not found'.format(request.name))
484 context.set_code(StatusCode.NOT_FOUND)
485 return Empty()
486
487 def delete_channel_termination(self, request, context):
488 log.info('grpc-request', request=request)
489
490 if '/' in request.id:
491 context.set_details(
492 'Malformed device id \'{}\''.format(request.id))
493 context.set_code(StatusCode.INVALID_ARGUMENT)
494 return Empty()
495
496 if '/' in request.name:
497 context.set_details(
498 'Malformed name \'{}\''.format(request.name))
499 context.set_code(StatusCode.INVALID_ARGUMENT)
500 return Empty()
501
502 try:
503 assert isinstance(request, ChannelterminationConfig)
504 except AssertionError:
505 context.set_details(
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400506 'Instance is not of Channel Termination')
Nikolay Titov89004ec2017-06-19 18:22:42 -0400507 context.set_code(StatusCode.INVALID_ARGUMENT)
508 return Empty()
509 except KeyError:
510 context.set_details(
511 'Device \'{}\' not found'.format(request.id))
512 context.set_code(StatusCode.NOT_FOUND)
513 return Empty()
514 try:
Nikolay Titove44c3d22017-08-03 15:27:37 -0400515 path = '/devices/{}/channel_terminations/{}'.format(
516 request.id, request.name)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400517 except KeyError:
518 context.set_details(
519 'channel termination \'{}\' not found'.format(request.name))
520 context.set_code(StatusCode.NOT_FOUND)
521 return Empty()
522 try:
523 log.debug('removing-channel-termination', name=request.name)
524 self.root.remove(path)
525 return Empty()
526
527 except KeyError:
528 context.set_details(
Nikolay Titove44c3d22017-08-03 15:27:37 -0400529 'Could not delete channel termination \'{}\''.format(
530 request.name))
Nikolay Titov89004ec2017-06-19 18:22:42 -0400531 context.set_code(StatusCode.INVALID_ARGUMENT)
532 return Empty()
533
534 def get_all_ont_ani_config(self, request, context):
535 log.info('grpc-request', request=request)
536 items = self.root.get('/ont_anis')
537 return AllOntaniConfig(ontani_config=items)
538
539 def create_ont_ani(self, request, context):
540 log.info('grpc-request', request=request)
541
542 try:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400543 assert isinstance(request, OntaniConfig), \
544 'Instance is not of Ont Ani'
Nikolay Titov89004ec2017-06-19 18:22:42 -0400545 assert self.validate_interface(request, context)
546 log.debug('creating-ont-ani', name=request.name)
547 self.root.add('/ont_anis', request)
548 return Empty()
549 except AssertionError, e:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400550 context.set_details(e.message)
551 context.set_code(StatusCode.INVALID_ARGUMENT)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400552 return Empty()
553 except KeyError:
554 context.set_details(
555 'Cannot create ontani \'{}\''.format(request.name))
556 context.set_code(StatusCode.NOT_FOUND)
557 return Empty()
558 except ValueError:
559 context.set_details(
Nikolay Titove44c3d22017-08-03 15:27:37 -0400560 'Duplicated ontani \'{}\' cannot be created'.format(
561 request.name))
Nikolay Titov89004ec2017-06-19 18:22:42 -0400562 context.set_code(StatusCode.INVALID_ARGUMENT)
563 return Empty()
564
565 def update_ont_ani(self, request, context):
566 log.info('grpc-request', request=request)
567
568 if '/' in request.name:
569 context.set_details(
570 'Malformed name \'{}\''.format(request.name))
571 context.set_code(StatusCode.INVALID_ARGUMENT)
572 return OntaniConfig()
573
574 try:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400575 assert isinstance(request, OntaniConfig), \
576 'Instance is not of Ont Ani'
Nikolay Titov89004ec2017-06-19 18:22:42 -0400577 assert self.validate_interface(request, context)
578
579 path = '/ont_anis/{}'.format(request.name)
580 log.debug('updating-ont-ani', name=request.name)
581 self.root.update(path, request, strict=True)
582 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -0400583 except AssertionError, e:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400584 context.set_details(e.message)
585 context.set_code(StatusCode.INVALID_ARGUMENT)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400586 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -0400587 except KeyError:
588 context.set_details(
589 'ontani \'{}\' not found'.format(request.name))
590 context.set_code(StatusCode.NOT_FOUND)
591 return Empty()
592
593 def delete_ont_ani(self, request, context):
594 log.info('grpc-request', request=request)
595
596 if '/' in request.name:
597 context.set_details(
598 'Malformed name \'{}\''.format(request.name))
599 context.set_code(StatusCode.INVALID_ARGUMENT)
600 return Empty()
601
602 try:
603 assert isinstance(request, OntaniConfig)
604
605 path = '/ont_anis/{}'.format(request.name)
606 log.debug('removing-ont-ani', name=request.name)
607 self.root.remove(path)
608 return Empty()
609
610 except AssertionError:
611 context.set_details(
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400612 'Instance is not of Ont Ani')
Nikolay Titov89004ec2017-06-19 18:22:42 -0400613 context.set_code(StatusCode.INVALID_ARGUMENT)
614 return Empty()
615
616 except KeyError:
617 context.set_details(
618 'ontani \'{}\' not found'.format(request.name))
619 context.set_code(StatusCode.NOT_FOUND)
620 return Empty()
621
622 def get_all_v_ont_ani_config(self, request, context):
623 log.info('grpc-request', request=request)
624 items = self.root.get('/v_ont_anis')
625 return AllVOntaniConfig(v_ontani_config=items)
626
627 def create_v_ont_ani(self, request, context):
628 log.info('grpc-request', request=request)
629
630 try:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400631 assert isinstance(request, VOntaniConfig), \
632 'Instance is not of VOnt Ani'
Nikolay Titov89004ec2017-06-19 18:22:42 -0400633 assert self.validate_interface(request, context)
634 log.debug('creating-vont-ani', name=request.name)
635 self.root.add('/v_ont_anis', request)
636 return Empty()
637 except AssertionError, e:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400638 context.set_details(e.message)
639 context.set_code(StatusCode.INVALID_ARGUMENT)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400640 return Empty()
641 except KeyError:
642 context.set_details(
643 'Cannot create vontani \'{}\''.format(request.name))
644 context.set_code(StatusCode.NOT_FOUND)
645 return Empty()
646 except ValueError:
647 context.set_details(
Nikolay Titove44c3d22017-08-03 15:27:37 -0400648 'Duplicated vontani \'{}\' cannot be created'.format(
649 request.name))
Nikolay Titov89004ec2017-06-19 18:22:42 -0400650 context.set_code(StatusCode.INVALID_ARGUMENT)
651 return Empty()
652
653 def update_v_ont_ani(self, request, context):
654 log.info('grpc-request', request=request)
655
656 if '/' in request.name:
657 context.set_details(
658 'Malformed name \'{}\''.format(request.name))
659 context.set_code(StatusCode.INVALID_ARGUMENT)
660 return VOntaniConfig()
661
662 try:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400663 assert isinstance(request, VOntaniConfig), \
664 'Instance is not of VOnt Ani'
Nikolay Titov89004ec2017-06-19 18:22:42 -0400665 assert self.validate_interface(request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400666 path = '/v_ont_anis/{}'.format(request.name)
667 log.debug('updating-vont-ani', name=request.name)
668 self.root.update(path, request, strict=True)
669 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -0400670 except AssertionError, e:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400671 context.set_details(e.message)
672 context.set_code(StatusCode.INVALID_ARGUMENT)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400673 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -0400674 except KeyError:
675 context.set_details(
676 'vontani \'{}\' not found'.format(request.name))
677 context.set_code(StatusCode.NOT_FOUND)
678 return Empty()
679
680 def delete_v_ont_ani(self, request, context):
681 log.info('grpc-request', request=request)
682
683 if '/' in request.name:
684 context.set_details(
685 'Malformed name \'{}\''.format(request.name))
686 context.set_code(StatusCode.INVALID_ARGUMENT)
687 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -0400688 try:
Nikolay Titov176f1db2017-08-10 12:38:43 -0400689 assert isinstance(request, VOntaniConfig), \
690 'Instance is not of vont ani'
691 vontani_ref_by_venet = next(
692 (venet for venet in self.root.get('/v_enets')
693 if venet.data.v_ontani_ref == request.name), None)
694 assert vontani_ref_by_venet is None, \
695 'VOntAni -- \'{}\' is referenced by VEnet'.format(
696 request.name)
697 vontani_ref_by_tcont = next(
698 (tcont for tcont in self.root.get('/tconts')
699 if tcont.interface_reference == request.name), None)
700 assert vontani_ref_by_tcont is None, \
701 'VOntAni -- \'{}\' is referenced by TCont'.format(
702 request.name)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400703 path = '/v_ont_anis/{}'.format(request.name)
704 log.debug('removing-vont-ani', name=request.name)
705 self.root.remove(path)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400706 return Empty()
Nikolay Titov176f1db2017-08-10 12:38:43 -0400707 except AssertionError, e:
708 context.set_details(e.message)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400709 context.set_code(StatusCode.INVALID_ARGUMENT)
710 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -0400711 except KeyError:
712 context.set_details(
713 'vontani \'{}\' not found'.format(request.name))
714 context.set_code(StatusCode.NOT_FOUND)
715 return Empty()
716
717 def get_all_v_enet_config(self, request, context):
718 log.info('grpc-request', request=request)
719 items = self.root.get('/v_enets')
720 return AllVEnetConfig(v_enet_config=items)
721
722 def create_v_enet(self, request, context):
723 log.info('grpc-request', request=request)
724
725 try:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400726 assert isinstance(request, VEnetConfig), \
727 'Instance is not of VEnet'
Nikolay Titov89004ec2017-06-19 18:22:42 -0400728 assert self.validate_interface(request, context)
729 log.debug('creating-venet', name=request.name)
730 self.root.add('/v_enets', request)
731 return Empty()
732 except AssertionError, e:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400733 context.set_details(e.message)
734 context.set_code(StatusCode.INVALID_ARGUMENT)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400735 return Empty()
736 except KeyError:
737 context.set_details(
738 'Cannot create venet \'{}\''.format(request.name))
739 context.set_code(StatusCode.NOT_FOUND)
740 return Empty()
741 except ValueError:
742 context.set_details(
Nikolay Titove44c3d22017-08-03 15:27:37 -0400743 'Duplicated venet \'{}\' cannot be created'.format(
744 request.name))
Nikolay Titov89004ec2017-06-19 18:22:42 -0400745 context.set_code(StatusCode.INVALID_ARGUMENT)
746 return Empty()
747
748 def update_v_enet(self, request, context):
749 log.info('grpc-request', request=request)
750
751 if '/' in request.name:
752 context.set_details(
753 'Malformed name \'{}\''.format(request.name))
754 context.set_code(StatusCode.INVALID_ARGUMENT)
755 return VEnetConfig()
756
757 try:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400758 assert isinstance(request, VEnetConfig), \
759 'Instance is not of VEnet'
Nikolay Titov89004ec2017-06-19 18:22:42 -0400760 assert self.validate_interface(request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400761 path = '/v_enets/{}'.format(request.name)
762 log.debug('updating-venet', name=request.name)
763 self.root.update(path, request, strict=True)
764 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -0400765 except AssertionError, e:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400766 context.set_details(e.message)
767 context.set_code(StatusCode.INVALID_ARGUMENT)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400768 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -0400769 except KeyError:
770 context.set_details(
771 'venet \'{}\' not found'.format(request.name))
772 context.set_code(StatusCode.NOT_FOUND)
773 return Empty()
774
775 def delete_v_enet(self, request, context):
776 log.info('grpc-request', request=request)
777
778 if '/' in request.name:
779 context.set_details(
780 'Malformed name \'{}\''.format(request.name))
781 context.set_code(StatusCode.INVALID_ARGUMENT)
782 return Empty()
783
784 try:
Nikolay Titov176f1db2017-08-10 12:38:43 -0400785 assert isinstance(request, VEnetConfig), \
786 'Instance is not of VEnet'
Nikolay Titov89004ec2017-06-19 18:22:42 -0400787 #assert device.admin_state == AdminState.DISABLED, \
788 #'Device to delete cannot be ' \
789 #'in admin state \'{}\''.format(device.admin_state)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400790 v_enet_ref_by_gemport = next(
791 (gemport for gemport in self.root.get('/gemports')
792 if gemport.itf_ref == request.name), None)
793 assert v_enet_ref_by_gemport is None, \
794 'The VEnet -- \'{}\' is referenced by Gemport'.format(
795 request.name)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400796 path = '/v_enets/{}'.format(request.name)
797 log.debug('removing-venet', name=request.name)
798 self.root.remove(path)
799 return Empty()
Nikolay Titov176f1db2017-08-10 12:38:43 -0400800 except AssertionError, e:
801 context.set_details(e.message)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400802 context.set_code(StatusCode.INVALID_ARGUMENT)
803 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -0400804 except KeyError:
805 context.set_details(
806 'venet \'{}\' not found'.format(request.name))
807 context.set_code(StatusCode.NOT_FOUND)
808 return Empty()
809
Nikolay Titov176f1db2017-08-10 12:38:43 -0400810 def get_all_traffic_descriptor_profile_data(self, request, context):
811 log.info('grpc-request', request=request)
812 items = self.root.get('/traffic_descriptor_profiles')
813 return AllTrafficDescriptorProfileData(
814 traffic_descriptor_profiles=items)
815
816 def create_traffic_descriptor_profile(self, request, context):
817 log.info('grpc-request', request=request)
818 try:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400819 assert isinstance(request, TrafficDescriptorProfileData), \
820 'Instance is not of Traffic Descriptor Profile'
Nikolay Titov176f1db2017-08-10 12:38:43 -0400821 assert self.validate_interface(request, context)
822 log.debug('creating-traffic-descriptor-profile', name=request.name)
823 self.root.add('/traffic_descriptor_profiles', request)
824 return Empty()
825 except AssertionError, e:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400826 context.set_details(e.message)
827 context.set_code(StatusCode.INVALID_ARGUMENT)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400828 return Empty()
829 except KeyError:
830 context.set_details(
831 'Cannot create traffic descriptor profile \'{}\''.format(
832 request.name))
833 context.set_code(StatusCode.NOT_FOUND)
834 return Empty()
835 except ValueError:
836 context.set_details(
837 'Duplicated traffic descriptor profile \'{}\' \
838 cannot be created'.format(request.name))
839 context.set_code(StatusCode.INVALID_ARGUMENT)
840 return Empty()
841
842 def update_traffic_descriptor_profile(self, request, context):
843 log.info('grpc-request', request=request)
844
845 if '/' in request.name:
846 context.set_details(
847 'Malformed name \'{}\''.format(request.name))
848 context.set_code(StatusCode.INVALID_ARGUMENT)
849 return TrafficDescriptorProfileData()
850
851 try:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400852 assert isinstance(request, TrafficDescriptorProfileData), \
853 'Instance is not of Traffic Descriptor Profile'
Nikolay Titov176f1db2017-08-10 12:38:43 -0400854 assert self.validate_interface(request, context)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400855 path = '/traffic_descriptor_profiles/{}'.format(request.name)
856 log.debug('updating-traffic-descriptor-profile',
857 name=request.name)
858 self.root.update(path, request, strict=True)
859 return Empty()
Nikolay Titov176f1db2017-08-10 12:38:43 -0400860 except AssertionError, e:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400861 context.set_details(e.message)
862 context.set_code(StatusCode.INVALID_ARGUMENT)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400863 return Empty()
Nikolay Titov176f1db2017-08-10 12:38:43 -0400864 except KeyError:
865 context.set_details(
866 'traffic descriptor profile \'{}\' not found'.format(
867 request.name))
868 context.set_code(StatusCode.NOT_FOUND)
869 return Empty()
870
871 def delete_traffic_descriptor_profile(self, request, context):
872 log.info('grpc-request', request=request)
873
874 if '/' in request.name:
875 context.set_details(
876 'Malformed name \'{}\''.format(request.name))
877 context.set_code(StatusCode.INVALID_ARGUMENT)
878 return Empty()
879
880 try:
881 assert isinstance(request, TrafficDescriptorProfileData), \
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400882 'Instance is not of Traffic Descriptor Profile'
Nikolay Titov176f1db2017-08-10 12:38:43 -0400883 tdp_ref_by_tcont = next(
884 (tcont for tcont in self.root.get('/tconts') if
885 tcont.traffic_descriptor_profile_ref == request.name), None)
886 assert tdp_ref_by_tcont is None, \
887 'The Traffic Descriptor Profile -- \'{}\' is referenced \
888 by TCont'.format(request.name)
889 path = '/traffic_descriptor_profiles/{}'.format(request.name)
890 log.debug('removing-traffic-descriptor-profile',
891 name=request.name)
892 self.root.remove(path)
893 return Empty()
894 except AssertionError, e:
895 context.set_details(e.message)
896 context.set_code(StatusCode.INVALID_ARGUMENT)
897 return Empty()
898 except KeyError:
899 context.set_details(
900 'traffic descriptor profile \'{}\' not found'.format(
901 request.name))
902 context.set_code(StatusCode.NOT_FOUND)
903 return Empty()
904
905 def get_all_tconts_config_data(self, request, context):
906 log.info('grpc-request', request=request)
907 items = self.root.get('/tconts')
908 return AllTcontsConfigData(tconts_config=items)
909
910 def create_tcont(self, request, context):
911 log.info('grpc-request', request=request)
912 try:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400913 assert isinstance(request, TcontsConfigData), \
914 'Instance is not of TCont'
Nikolay Titov176f1db2017-08-10 12:38:43 -0400915 assert self.validate_interface(request, context)
Nikolay Titov7253ff22017-08-14 18:24:17 -0400916 cg_name = self.extract_channel_group_from_request(request,
917 'v_ont_anis', request.interface_reference)
Chip Boling97bef1e2017-08-29 11:44:28 -0500918 if request.alloc_id == 0:
919 _id = self.cg_dict[cg_name]['alloc_id'].get_next()
920 assert _id is not None, \
921 'Fail to allocate id for TCont'
922 request.alloc_id = _id
923 else:
924 _id = self.cg_dict[cg_name]['alloc_id'].allocate(request.alloc_id)
925 assert _id == request.alloc_id, \
926 'Fail to allocate id for TCont'
927
Nikolay Titov176f1db2017-08-10 12:38:43 -0400928 log.debug('creating-tcont', name=request.name)
929 self.root.add('/tconts', request)
930 return Empty()
931 except AssertionError, e:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400932 context.set_details(e.message)
933 context.set_code(StatusCode.INVALID_ARGUMENT)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400934 return Empty()
935 except KeyError:
936 context.set_details(
937 'Cannot create tcont \'{}\''.format(request.name))
938 context.set_code(StatusCode.NOT_FOUND)
939 return Empty()
940 except ValueError:
Nikolay Titov7253ff22017-08-14 18:24:17 -0400941 self.cg_dict[cg_name]['alloc_id'].release(_id)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400942 context.set_details(
943 'Duplicated tcont \'{}\' cannot be created'.format(
944 request.name))
945 context.set_code(StatusCode.INVALID_ARGUMENT)
946 return Empty()
947
948 def update_tcont(self, request, context):
949 log.info('grpc-request', request=request)
950 if '/' in request.name:
951 context.set_details(
952 'Malformed name \'{}\''.format(request.name))
953 context.set_code(StatusCode.INVALID_ARGUMENT)
954 return TcontsConfigData()
955 try:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400956 assert isinstance(request, TcontsConfigData), \
957 'Instance is not of TCont'
Nikolay Titov176f1db2017-08-10 12:38:43 -0400958 assert self.validate_interface(request, context)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400959 path = '/tconts/{}'.format(request.name)
Nikolay Titov7253ff22017-08-14 18:24:17 -0400960 tcont = self.root.get(path)
961 request.alloc_id = tcont.alloc_id
Nikolay Titov176f1db2017-08-10 12:38:43 -0400962 log.debug('updating-tcont', name=request.name)
963 self.root.update(path, request, strict=True)
964 return Empty()
965 except AssertionError, e:
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400966 context.set_details(e.message)
967 context.set_code(StatusCode.INVALID_ARGUMENT)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400968 return Empty()
969 except KeyError:
970 context.set_details(
971 'tcont \'{}\' not found'.format(request.name))
972 context.set_code(StatusCode.NOT_FOUND)
973 return Empty()
974
975 def delete_tcont(self, request, context):
976 log.info('grpc-request', request=request)
977 if '/' in request.name:
978 context.set_details(
979 'Malformed name \'{}\''.format(request.name))
980 context.set_code(StatusCode.INVALID_ARGUMENT)
981 return Empty()
982 try:
983 assert isinstance(request, TcontsConfigData), \
984 'Instance is not of TCont'
985 tcont_ref_by_gemport = next(
986 (gemport for gemport in self.root.get('/gemports')
987 if gemport.tcont_ref == request.name), None)
988 assert tcont_ref_by_gemport is None, \
989 'The Tcont -- \'{}\' is referenced by GemPort'.format(
990 request.name)
991 path = '/tconts/{}'.format(request.name)
Nikolay Titov7253ff22017-08-14 18:24:17 -0400992 tcont = self.root.get(path)
993 cg_name = self.extract_channel_group_from_request(tcont,
994 'v_ont_anis', tcont.interface_reference)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400995 log.debug('removing-tcont', name=request.name)
996 self.root.remove(path)
Nikolay Titov7253ff22017-08-14 18:24:17 -0400997 self.cg_dict[cg_name]['alloc_id'].release(tcont.alloc_id)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400998 return Empty()
999 except AssertionError, e:
1000 context.set_details(e.message)
1001 context.set_code(StatusCode.INVALID_ARGUMENT)
1002 return Empty()
1003 except KeyError:
1004 context.set_details(
1005 'tcont \'{}\' not found'.format(request.name))
1006 context.set_code(StatusCode.NOT_FOUND)
1007 return Empty()
1008
1009 def get_all_gemports_config_data(self, request, context):
1010 log.info('grpc-request', request=request)
1011 items = self.root.get('/gemports')
1012 return AllGemportsConfigData(gemports_config=items)
1013
1014 def create_gem_port(self, request, context):
1015 log.info('grpc-request', request=request)
1016 try:
Nikolay Titov4e1c3702017-08-23 12:41:57 -04001017 assert isinstance(request, GemportsConfigData), \
1018 'Instance is not of GemPort'
Nikolay Titov176f1db2017-08-10 12:38:43 -04001019 assert self.validate_interface(request, context)
Nikolay Titov7253ff22017-08-14 18:24:17 -04001020 cg_name = self.extract_channel_group_from_request(request,
1021 'v_enets', request.itf_ref)
Chip Boling97bef1e2017-08-29 11:44:28 -05001022 if request.gemport_id == 0:
1023 _id = self.cg_dict[cg_name]['gemport_id'].get_next()
1024 assert _id is not None, \
1025 'Fail to allocate id for GemPort'
1026 request.gemport_id = _id
1027 else:
1028 _id = self.cg_dict[cg_name]['gemport_id'].allocate(request.gemport_id)
1029 assert _id == request.gemport_id, \
1030 'Fail to allocate id for GemPort'
1031
Nikolay Titov176f1db2017-08-10 12:38:43 -04001032 log.debug('creating-gemport', name=request.name)
1033 self.root.add('/gemports', request)
1034 return Empty()
1035 except AssertionError, e:
Nikolay Titov4e1c3702017-08-23 12:41:57 -04001036 context.set_details(e.message)
1037 context.set_code(StatusCode.INVALID_ARGUMENT)
Nikolay Titov176f1db2017-08-10 12:38:43 -04001038 return Empty()
1039 except KeyError:
1040 context.set_details(
1041 'Cannot create gemport \'{}\''.format(request.name))
1042 context.set_code(StatusCode.NOT_FOUND)
1043 return Empty()
1044 except ValueError:
Nikolay Titov7253ff22017-08-14 18:24:17 -04001045 self.cg_dict[cg_name]['gemport_id'].release(_id)
Nikolay Titov176f1db2017-08-10 12:38:43 -04001046 context.set_details(
1047 'Duplicated gemport \'{}\' cannot be created'.format(
1048 request.name))
1049 context.set_code(StatusCode.INVALID_ARGUMENT)
1050 return Empty()
1051
1052 def update_gem_port(self, request, context):
1053 log.info('grpc-request', request=request)
1054 if '/' in request.name:
1055 context.set_details(
1056 'Malformed name \'{}\''.format(request.name))
1057 context.set_code(StatusCode.INVALID_ARGUMENT)
1058 return GemportsConfigData()
1059 try:
Nikolay Titov4e1c3702017-08-23 12:41:57 -04001060 assert isinstance(request, GemportsConfigData), \
1061 'Instance is not of GemPort'
Nikolay Titov176f1db2017-08-10 12:38:43 -04001062 assert self.validate_interface(request, context)
Nikolay Titov176f1db2017-08-10 12:38:43 -04001063 path = '/gemports/{}'.format(request.name)
Nikolay Titov7253ff22017-08-14 18:24:17 -04001064 gemport = self.root.get(path)
1065 request.gemport_id = gemport.gemport_id
Nikolay Titov176f1db2017-08-10 12:38:43 -04001066 log.debug('updating-gemport', name=request.name)
1067 self.root.update(path, request, strict=True)
1068 return Empty()
1069 except AssertionError, e:
Nikolay Titov4e1c3702017-08-23 12:41:57 -04001070 context.set_details(e.message)
1071 context.set_code(StatusCode.INVALID_ARGUMENT)
Nikolay Titov176f1db2017-08-10 12:38:43 -04001072 return Empty()
1073 except KeyError:
1074 context.set_details(
1075 'gemport \'{}\' not found'.format(request.name))
1076 context.set_code(StatusCode.NOT_FOUND)
1077 return Empty()
1078
1079 def delete_gem_port(self, request, context):
1080 log.info('grpc-request', request=request)
1081 if '/' in request.name:
1082 context.set_details(
1083 'Malformed name \'{}\''.format(request.name))
1084 context.set_code(StatusCode.INVALID_ARGUMENT)
1085 return Empty()
1086 try:
1087 assert isinstance(request, GemportsConfigData)
1088 path = '/gemports/{}'.format(request.name)
Nikolay Titov7253ff22017-08-14 18:24:17 -04001089 gemport = self.root.get(path)
1090 cg_name = self.extract_channel_group_from_request(gemport,
1091 'v_enets', gemport.itf_ref)
Nikolay Titov176f1db2017-08-10 12:38:43 -04001092 log.debug('removing-gemport', name=request.name)
1093 self.root.remove(path)
Nikolay Titov7253ff22017-08-14 18:24:17 -04001094 self.cg_dict[cg_name]['gemport_id'].release(gemport.gemport_id)
Nikolay Titov176f1db2017-08-10 12:38:43 -04001095 return Empty()
1096 except AssertionError:
Nikolay Titov4e1c3702017-08-23 12:41:57 -04001097 context.set_details('Instance is not of GemPort')
Nikolay Titov176f1db2017-08-10 12:38:43 -04001098 context.set_code(StatusCode.INVALID_ARGUMENT)
1099 return Empty()
1100 except KeyError:
1101 context.set_details(
1102 'gemport \'{}\' not found'.format(request.name))
1103 context.set_code(StatusCode.NOT_FOUND)
1104 return Empty()
1105
Nikolay Titov89004ec2017-06-19 18:22:42 -04001106 def validate_interface(self, request, context):
1107 try:
1108 if(isinstance(request, ChannelgroupConfig)):
1109 assert isinstance(request, ChannelgroupConfig)
1110 channelgroup = request
Nikolay Titove44c3d22017-08-03 15:27:37 -04001111 assert channelgroup.name != '', \
1112 'Channel Group name is mandatory'
Nikolay Titov89004ec2017-06-19 18:22:42 -04001113 assert 0 <= channelgroup.data.polling_period <= 864000, \
Nikolay Titove44c3d22017-08-03 15:27:37 -04001114 'Channel Group polling period must be in range of \
1115 [1, 864000]'
Nikolay Titov89004ec2017-06-19 18:22:42 -04001116 return True
1117 elif(isinstance(request, ChannelpartitionConfig)):
1118 assert isinstance(request, ChannelpartitionConfig)
1119 channelpartition = request
Nikolay Titove44c3d22017-08-03 15:27:37 -04001120 assert channelpartition.name != '', \
1121 'Channel Partition name is mandatory'
Nikolay Titov89004ec2017-06-19 18:22:42 -04001122
1123 assert channelpartition.data.channelgroup_ref != '', \
1124 'Channel Partition must reference a channel group'
Nikolay Titove44c3d22017-08-03 15:27:37 -04001125 assert self.get_ref_data(
1126 request, context, "channel_groups",
1127 request.data.channelgroup_ref), \
1128 'Reference to channel group -- \'{}\' not found'.format(
1129 request.data.channelgroup_ref)
Nikolay Titov89004ec2017-06-19 18:22:42 -04001130
1131 assert 0 <= channelpartition.data.closest_ont_distance <= 40, \
Nikolay Titove44c3d22017-08-03 15:27:37 -04001132 'Channel Partition closest ont distance must be in range \
1133 of [0, 40]'
Nikolay Titov89004ec2017-06-19 18:22:42 -04001134
Nikolay Titove44c3d22017-08-03 15:27:37 -04001135 assert channelpartition.data.differential_fiber_distance \
1136 == 0 or \
1137 channelpartition.data.differential_fiber_distance == 20 \
1138 or channelpartition.data.differential_fiber_distance \
1139 == 34 or \
Nikolay Titov89004ec2017-06-19 18:22:42 -04001140 channelpartition.data.differential_fiber_distance == 40, \
Nikolay Titove44c3d22017-08-03 15:27:37 -04001141 'Channel Partition differential fiber distance must be \
1142 [20 | 34 | 40]'
Nikolay Titov89004ec2017-06-19 18:22:42 -04001143 return True
1144 elif(isinstance(request, ChannelpairConfig)):
1145 assert isinstance(request, ChannelpairConfig)
1146 channelpair = request
1147 channelpair_type = ["channelpair", "channelpair_xgs"]
Nikolay Titove44c3d22017-08-03 15:27:37 -04001148 channelpair_speed_type = ["unplanned_cp_speed",
1149 "down_10_up_10", "down_10_up_2_5",
1150 "down_2_5_up_2_5"]
Nikolay Titov89004ec2017-06-19 18:22:42 -04001151 assert channelpair.name != '', 'Channel Pair name is mandatory'
1152
1153 if channelpair.data.channelgroup_ref:
Nikolay Titove44c3d22017-08-03 15:27:37 -04001154 assert self.get_ref_data(
1155 request, context, "channel_groups",
1156 request.data.channelgroup_ref), \
Nikolay Titov89004ec2017-06-19 18:22:42 -04001157 'Reference to channel group -- \'{}\' not found'\
1158 .format(request.data.channelgroup_ref)
Nikolay Titov4e1c3702017-08-23 12:41:57 -04001159 '''
1160 @todo: For VOLTHA 1.0, make this reference mandatory until
1161 VOL-314 & VOL-356 are implemented.
1162 '''
1163 assert channelpair.data.channelpartition_ref != '', \
1164 'Channel Pair must reference an existing Channel Partition'
1165 assert self.get_ref_data(
1166 request, context, "channel_partitions",
1167 request.data.channelpartition_ref), \
1168 'Reference to channel partition -- \'{}\' not found'\
1169 .format(request.data.channelpartition_ref)
Nikolay Titov89004ec2017-06-19 18:22:42 -04001170
Nikolay Titove44c3d22017-08-03 15:27:37 -04001171 assert channelpair.data.channelpair_type != '', \
1172 'Channel Pair type is mandatory'
Nikolay Titov89004ec2017-06-19 18:22:42 -04001173 assert channelpair.data.channelpair_type in channelpair_type, \
Nikolay Titove44c3d22017-08-03 15:27:37 -04001174 'Invalid value for Channel Pair type \'{}\''\
1175 .format(channelpair.data.channelpair_type)
1176 assert channelpair.data.channelpair_linerate in \
1177 channelpair_speed_type, \
1178 'Invalid value for Channel Pair linerate \'{}\''\
1179 .format(channelpair.data.channelpair_linerate)
Nikolay Titov89004ec2017-06-19 18:22:42 -04001180 return True
1181 elif(isinstance(request, ChannelterminationConfig)):
1182 assert isinstance(request, ChannelterminationConfig)
1183 channeltermin = request
Nikolay Titove44c3d22017-08-03 15:27:37 -04001184 assert '/' not in channeltermin.id, \
1185 'Malformed device id \'{}\''.format(request.id)
Nikolay Titov89004ec2017-06-19 18:22:42 -04001186 assert channeltermin.id != '', 'Device ID is mandatory'
Nikolay Titove44c3d22017-08-03 15:27:37 -04001187 assert channeltermin.name != '', \
1188 'Channel Termination name is mandatory'
Nikolay Titov4e1c3702017-08-23 12:41:57 -04001189 '''
1190 @todo: For VOLTHA 1.0, make this reference mandatory until
1191 VOL-314 & VOL-356 are implemented.
1192 '''
1193 assert channeltermin.data.channelpair_ref != '', \
1194 'Channel Termination must reference Channel Pair'
1195 assert self.get_ref_data(
1196 request, context, "channel_pairs",
1197 request.data.channelpair_ref), \
1198 'Reference to channel pair -- \'{}\' not found'\
1199 .format(request.data.channelpair_ref)
Nikolay Titov89004ec2017-06-19 18:22:42 -04001200
1201 assert 0 <= channeltermin.data.ber_calc_period <= 864000, \
Nikolay Titove44c3d22017-08-03 15:27:37 -04001202 'Channel Termination ber calc period must be in range of \
1203 [1, 864000]'
Nikolay Titov89004ec2017-06-19 18:22:42 -04001204 return True
1205 elif(isinstance(request, OntaniConfig)):
1206 assert isinstance(request, OntaniConfig)
1207 ontani = request
1208 assert ontani.name != '', 'OntAni name is mandatory'
1209 return True
1210 elif(isinstance(request, VOntaniConfig)):
1211 assert isinstance(request, VOntaniConfig)
1212 vontani = request
1213 assert vontani.name != '', 'VOntAni name is mandatory'
Nikolay Titov4e1c3702017-08-23 12:41:57 -04001214 assert vontani.data.parent_ref != '', \
1215 'VOntAni must reference an existing Channel Partition'
1216 assert self.get_ref_data(
1217 request, context, "channel_partitions",
1218 request.data.parent_ref), \
1219 'Reference to channel partition -- \'{}\' not found'\
1220 .format(request.data.parent_ref)
1221 '''
1222 @todo: For VOLTHA 1.0, make this reference mandatory until
1223 VOL-314 & VOL-356 are implemented.
1224 '''
1225 assert vontani.data.preferred_chanpair != '', \
1226 'VOntAni must reference preferred Channel Pair'
1227 #if vontani.data.preferred_chanpair:
1228 assert self.get_ref_data(
1229 request, context, "channel_pairs",
1230 request.data.preferred_chanpair), \
1231 'Preferred channel pair -- \'{}\' not found'\
1232 .format(request.data.preferred_chanpair)
Nikolay Titov89004ec2017-06-19 18:22:42 -04001233 if vontani.data.protection_chanpair:
Nikolay Titove44c3d22017-08-03 15:27:37 -04001234 assert self.get_ref_data(
1235 request, context, "channel_pairs",
1236 request.data.protection_chanpair), \
1237 'Protection channel pair -- \'{}\' not found'\
1238 .format(request.data.protection_chanpair)
Nikolay Titov89004ec2017-06-19 18:22:42 -04001239
1240 assert 0 <= len(vontani.data.expected_registration_id) <= 36, \
Nikolay Titove44c3d22017-08-03 15:27:37 -04001241 'VOnt Ani expected registration id string length must be \
1242 in range of [0, 36]'
Nikolay Titov89004ec2017-06-19 18:22:42 -04001243 assert 0 <= vontani.data.onu_id <= 1020, \
1244 'VOnt Ani ONU id must be in range of [0, 1020]'
1245
1246 items = self.root.get('/v_ont_anis')
1247 for item in items:
1248 if item.data.parent_ref == vontani.data.parent_ref or \
Nikolay Titove44c3d22017-08-03 15:27:37 -04001249 item.data.preferred_chanpair == \
1250 vontani.data.preferred_chanpair or \
1251 item.data.protection_chanpair == \
1252 vontani.data.protection_chanpair:
1253 if item.name != vontani.name:
1254 assert item.data.onu_id != vontani.data.onu_id, \
1255 'VOnt Ani ONU id -- \'{}\' already exists, \
1256 but must be unique within channel group'\
1257 .format(vontani.data.onu_id)
Nikolay Titov89004ec2017-06-19 18:22:42 -04001258 return True
1259 elif(isinstance(request, VEnetConfig)):
1260 assert isinstance(request, VEnetConfig)
1261 venet = request
1262 assert venet.name != '', 'VEnet name is mandatory'
Nikolay Titov4e1c3702017-08-23 12:41:57 -04001263 assert venet.data.v_ontani_ref != '', \
1264 'VEnet must reference an existing VOntAni'
1265 assert self.get_ref_data(
1266 request, context, "v_ont_anis", venet.data.v_ontani_ref), \
1267 'Reference to VOntAni -- \'{}\' not found'\
1268 .format(venet.data.v_ontani_ref)
Nikolay Titov89004ec2017-06-19 18:22:42 -04001269 return True
Nikolay Titov176f1db2017-08-10 12:38:43 -04001270 elif(isinstance(request, TrafficDescriptorProfileData)):
1271 assert isinstance(request, TrafficDescriptorProfileData)
1272 traffic_descriptor = request
1273 assert traffic_descriptor.name != '', \
1274 'Traffic Descriptor Profile name is mandatory'
1275 assert traffic_descriptor.fixed_bandwidth != '', \
1276 'Fixed bandwidth of Traffic Descriptor is mandatory'
1277 assert traffic_descriptor.assured_bandwidth != '', \
1278 'Assured bandwidth of Traffic Descriptor is mandatory'
1279 assert traffic_descriptor.maximum_bandwidth != '', \
1280 'Maximum bandwidth of Traffic Descriptor is mandatory'
1281 assert 0 <= traffic_descriptor.priority <= 8, \
1282 'Traffic Descriptor Profile priority for or scheduling \
1283 traffic on a TCont must be in range of [1, 8]'
1284 return True
1285 elif(isinstance(request, TcontsConfigData)):
1286 assert isinstance(request, TcontsConfigData)
1287 tcont = request
1288 assert tcont.name != '', 'TCont name is mandatory'
1289 assert tcont.interface_reference != '', \
1290 'TCont must reference a vont ani interface'
1291 assert tcont.traffic_descriptor_profile_ref != '', \
1292 'TCont must reference an existing traffic descriptor \
1293 profile'
1294 assert self.get_ref_data(
1295 request, context, "v_ont_anis",
1296 tcont.interface_reference), \
1297 'Reference to vont ani interface -- \'{}\' not found'\
1298 .format(tcont.interface_reference)
1299 assert self.get_ref_data(
1300 request, context, "traffic_descriptor_profiles",
1301 tcont.traffic_descriptor_profile_ref), \
1302 'Reference to traffic descriptor profile -- \'{}\' \
1303 not found'.format(tcont.traffic_descriptor_profile_ref)
1304 return True
1305 elif(isinstance(request, GemportsConfigData)):
1306 assert isinstance(request, GemportsConfigData)
1307 gemport = request
1308 assert gemport.name != '', 'Gemport name is mandatory'
1309 assert gemport.itf_ref != '', \
Nikolay Titov4e1c3702017-08-23 12:41:57 -04001310 'GemPort must reference an existing VEnet interface'
Nikolay Titov176f1db2017-08-10 12:38:43 -04001311 assert self.get_ref_data(
1312 request, context, "v_enets", gemport.itf_ref), \
1313 'Reference to VEnet interface -- \'{}\' not found'\
1314 .format(gemport.itf_ref)
1315 assert 0 <= gemport.traffic_class <= 7, \
1316 'Traffic class value for Gemport \
1317 must be in range of [0, 7]'
Nikolay Titov4e1c3702017-08-23 12:41:57 -04001318 '''
1319 @todo: For VOLTHA 1.0, make this reference mandatory until
1320 VOL-314 & VOL-356 are implemented.
1321 '''
1322 assert gemport.tcont_ref != '', \
1323 'GemPort must reference an existing TCont'
1324 assert self.get_ref_data(
1325 request, context, "tconts", gemport.tcont_ref), \
1326 'Reference to tcont -- \'{}\' not found'\
1327 .format(gemport.tcont_ref)
Nikolay Titov176f1db2017-08-10 12:38:43 -04001328 return True
Nikolay Titov89004ec2017-06-19 18:22:42 -04001329 else:
1330 return False
1331 except AssertionError, e:
1332 context.set_details(e.message)
1333 context.set_code(StatusCode.INVALID_ARGUMENT)
1334 return False
1335
1336 def get_ref_data(self, request, context, interface, reference):
1337 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
1338
1339 try:
1340 path = '/{}/'.format(interface)
1341 self.root.get(path + reference, depth=depth)
Nikolay Titove44c3d22017-08-03 15:27:37 -04001342 log.info('reference-for-{}-found-\'{}\''\
1343 .format(interface, reference))
Nikolay Titov89004ec2017-06-19 18:22:42 -04001344 return True
1345
1346 except KeyError:
Nikolay Titove44c3d22017-08-03 15:27:37 -04001347 log.info('reference-for-{}-not-found-\'{}\''\
1348 .format(interface, reference))
Nikolay Titov89004ec2017-06-19 18:22:42 -04001349 return False
Nikolay Titov7253ff22017-08-14 18:24:17 -04001350
1351 def extract_channel_group_from_request(self, request, interface,
1352 reference):
1353 try:
1354 path = '/{}/{}'.format(interface, reference)
1355 item = self.root.get(path)
1356 if isinstance(item, ChannelgroupConfig):
1357 return item.name
1358 elif isinstance(item, VEnetConfig):
1359 return self.extract_channel_group_from_request(Empty(),
1360 'v_ont_anis', item.data.v_ontani_ref)
1361 elif isinstance(item, VOntaniConfig):
1362 return self.extract_channel_group_from_request(Empty(),
1363 'channel_partitions', item.data.parent_ref)
1364 elif isinstance(item, ChannelpartitionConfig):
1365 return self.extract_channel_group_from_request(Empty(),
1366 'channel_groups', item.data.channelgroup_ref)
1367 except KeyError:
1368 log.info('reference-for-{}-not found'.format(interface))
1369 return Empty()