blob: 4f5d09c3f315d8436ac1a407d1119f8a7af8f4bd [file] [log] [blame]
Zsolt Haraszti3eb27a52017-01-03 21:56:48 -08001# Copyright 2017 the original author or authors.
Zsolt Haraszti66862032016-11-28 14:28:39 -08002#
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#
Zsolt Haraszti3300f742017-01-09 01:14:20 -080015from Queue import Empty as QueueEmpty
Zsolt Haraszti66862032016-11-28 14:28:39 -080016from uuid import uuid4
17
18import structlog
Zsolt Haraszti3300f742017-01-09 01:14:20 -080019from google.protobuf.empty_pb2 import Empty
Zsolt Haraszti66862032016-11-28 14:28:39 -080020from grpc import StatusCode
Stephane Barbarie2940dac2017-08-18 14:15:17 -040021from grpc._channel import _Rendezvous
Zsolt Haraszti66862032016-11-28 14:28:39 -080022
23from common.utils.grpc_utils import twisted_async
Stephane Barbarie2940dac2017-08-18 14:15:17 -040024from twisted.internet import task
khenaidooa8588f22017-06-16 12:13:34 -040025from common.utils.id_generation import create_cluster_device_id
Zsolt Haraszti66862032016-11-28 14:28:39 -080026from voltha.core.config.config_root import ConfigRoot
Zsolt Haraszti217a12e2016-12-19 16:37:55 -080027from voltha.protos.openflow_13_pb2 import PacketIn, Flows, FlowGroups, \
28 ofp_port_status
Zsolt Haraszti66862032016-11-28 14:28:39 -080029from voltha.protos.voltha_pb2 import \
30 add_VolthaLocalServiceServicer_to_server, VolthaLocalServiceServicer, \
31 VolthaInstance, Adapters, LogicalDevices, LogicalDevice, Ports, \
32 LogicalPorts, Devices, Device, DeviceType, \
Stephane Barbarie4db8ca22017-04-24 10:30:20 -040033 DeviceTypes, DeviceGroups, DeviceGroup, AdminState, OperStatus, ChangeEvent, \
Stephane Barbarie2940dac2017-08-18 14:15:17 -040034 AlarmFilter, AlarmFilters, SelfTestResponse, OfAgentSubscriber
Lydia Fang01f2e852017-06-28 17:24:58 -070035from voltha.protos.device_pb2 import PmConfigs, Images, ImageDownload, ImageDownloads
36from voltha.protos.common_pb2 import OperationResp
Stephane Barbarie2940dac2017-08-18 14:15:17 -040037from voltha.protos.bbf_fiber_base_pb2 import AllMulticastDistributionSetData, AllMulticastGemportsConfigData
Zsolt Haraszti66862032016-11-28 14:28:39 -080038from voltha.registry import registry
Nikolay Titov89004ec2017-06-19 18:22:42 -040039from requests.api import request
Stephane Barbarie2940dac2017-08-18 14:15:17 -040040from common.utils.asleep import asleep
Zsolt Haraszti66862032016-11-28 14:28:39 -080041
42log = structlog.get_logger()
43
44
45class LocalHandler(VolthaLocalServiceServicer):
khenaidoo032d3302017-06-09 14:50:04 -040046 def __init__(self, core, instance_id, core_store_id, **init_kw):
Zsolt Haraszti66862032016-11-28 14:28:39 -080047 self.core = core
khenaidoo032d3302017-06-09 14:50:04 -040048 self.instance_id = instance_id
49 self.core_store_id = core_store_id
Zsolt Haraszti66862032016-11-28 14:28:39 -080050 self.init_kw = init_kw
51 self.root = None
khenaidoo032d3302017-06-09 14:50:04 -040052 self.started_with_existing_data = False
Zsolt Haraszti66862032016-11-28 14:28:39 -080053 self.stopped = False
54
Stephane Barbarie2940dac2017-08-18 14:15:17 -040055 self.restart_delay = 2
56 self.subscriber = None
57 self.ofagent_heartbeat_count = 0
58 self.ofagent_heartbeat_max_count = 3
59 self.ofagent_heartbeat_delay = 5
60 self.ofagent_heartbeat_lc = None
61 self.ofagent_is_alive = True
62
Ryan Van Gilder5a0ab622017-03-01 16:39:25 -080063 def start(self, config_backend=None):
Zsolt Haraszti66862032016-11-28 14:28:39 -080064 log.debug('starting')
Ryan Van Gilder5a0ab622017-03-01 16:39:25 -080065 if config_backend:
66 if 'root' in config_backend:
khenaidoo032d3302017-06-09 14:50:04 -040067 # This is going to block the entire reactor until loading is
68 # completed
69 log.info('loading-config-from-persisted-backend')
70 try:
71 self.root = ConfigRoot.load(VolthaInstance,
72 kv_store=config_backend)
73 self.started_with_existing_data = True
74 except Exception, e:
75 log.exception('Failure-loading-from-backend', e=e)
Ryan Van Gilder5a0ab622017-03-01 16:39:25 -080076 else:
khenaidoo032d3302017-06-09 14:50:04 -040077 log.info('initializing-a-new-config')
Khen Nursimulud068d812017-03-06 11:44:18 -050078 self.root = ConfigRoot(VolthaInstance(**self.init_kw),
79 kv_store=config_backend)
Ryan Van Gilder5a0ab622017-03-01 16:39:25 -080080 else:
81 self.root = ConfigRoot(VolthaInstance(**self.init_kw))
82
Nikolay Titov89004ec2017-06-19 18:22:42 -040083 self.core.xpon_handler.start(self.root)
84
Zsolt Haraszti66862032016-11-28 14:28:39 -080085 log.info('started')
86 return self
87
khenaidoocbe30832017-08-25 10:43:27 -040088 def register_grpc_service(self):
89 log.debug('registering')
90 registry('grpc_server').register(
91 add_VolthaLocalServiceServicer_to_server, self)
92 log.info('registered')
93
94
Zsolt Haraszti66862032016-11-28 14:28:39 -080095 def stop(self):
96 log.debug('stopping')
97 self.stopped = True
Stephane Barbarie2940dac2017-08-18 14:15:17 -040098
99 if self.ofagent_heartbeat_lc is not None:
100 self.ofagent_heartbeat_lc.stop()
101
102 self._ofagent_session_termination()
103
Zsolt Haraszti66862032016-11-28 14:28:39 -0800104 log.info('stopped')
105
106 def get_proxy(self, path, exclusive=False):
107 return self.root.get_proxy(path, exclusive)
108
khenaidoo032d3302017-06-09 14:50:04 -0400109 def has_started_with_existing_data(self):
110 return self.started_with_existing_data
111
Zsolt Haraszti66862032016-11-28 14:28:39 -0800112 # gRPC service method implementations. BE CAREFUL; THESE ARE CALLED ON
113 # the gRPC threadpool threads.
114
115 @twisted_async
116 def GetVolthaInstance(self, request, context):
117 log.info('grpc-request', request=request)
118 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
119 res = self.root.get('/', depth=depth)
120 return res
121
122 @twisted_async
123 def GetHealth(self, request, context):
124 log.info('grpc-request', request=request)
125 return self.root.get('/health')
126
127 @twisted_async
128 def ListAdapters(self, request, context):
129 log.info('grpc-request', request=request)
130 items = self.root.get('/adapters')
khenaidooc4832162017-09-20 11:55:04 -0400131 sorted_items = sorted(items, key=lambda i: i.id)
132 return Adapters(items=sorted_items)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800133
134 @twisted_async
135 def ListLogicalDevices(self, request, context):
136 log.info('grpc-request', request=request)
137 items = self.root.get('/logical_devices')
138 return LogicalDevices(items=items)
139
140 @twisted_async
141 def GetLogicalDevice(self, request, context):
142 log.info('grpc-request', request=request)
143
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800144 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
145
Zsolt Haraszti66862032016-11-28 14:28:39 -0800146 if '/' in request.id:
147 context.set_details(
148 'Malformed logical device id \'{}\''.format(request.id))
149 context.set_code(StatusCode.INVALID_ARGUMENT)
150 return LogicalDevice()
151
152 try:
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800153 return self.root.get('/logical_devices/' + request.id, depth=depth)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800154 except KeyError:
155 context.set_details(
156 'Logical device \'{}\' not found'.format(request.id))
157 context.set_code(StatusCode.NOT_FOUND)
158 return LogicalDevice()
159
160 @twisted_async
161 def ListLogicalDevicePorts(self, request, context):
162 log.info('grpc-request', request=request)
163
164 if '/' in request.id:
165 context.set_details(
166 'Malformed logical device id \'{}\''.format(request.id))
167 context.set_code(StatusCode.INVALID_ARGUMENT)
168 return LogicalPorts()
169
170 try:
Khen Nursimulud068d812017-03-06 11:44:18 -0500171 items = self.root.get(
172 '/logical_devices/{}/ports'.format(request.id))
Zsolt Haraszti66862032016-11-28 14:28:39 -0800173 return LogicalPorts(items=items)
174 except KeyError:
175 context.set_details(
176 'Logical device \'{}\' not found'.format(request.id))
177 context.set_code(StatusCode.NOT_FOUND)
178 return LogicalPorts()
179
180 @twisted_async
181 def ListLogicalDeviceFlows(self, request, context):
182 log.info('grpc-request', request=request)
183
184 if '/' in request.id:
185 context.set_details(
186 'Malformed logical device id \'{}\''.format(request.id))
187 context.set_code(StatusCode.INVALID_ARGUMENT)
188 return Flows()
189
190 try:
Khen Nursimulud068d812017-03-06 11:44:18 -0500191 flows = self.root.get(
192 '/logical_devices/{}/flows'.format(request.id))
Zsolt Haraszti66862032016-11-28 14:28:39 -0800193 return flows
194 except KeyError:
195 context.set_details(
196 'Logical device \'{}\' not found'.format(request.id))
197 context.set_code(StatusCode.NOT_FOUND)
198 return Flows()
199
Zsolt Haraszti66862032016-11-28 14:28:39 -0800200 @twisted_async
201 def UpdateLogicalDeviceFlowTable(self, request, context):
202 log.info('grpc-request', request=request)
203
204 if '/' in request.id:
205 context.set_details(
206 'Malformed logical device id \'{}\''.format(request.id))
207 context.set_code(StatusCode.INVALID_ARGUMENT)
208 return Empty()
209
210 try:
211 agent = self.core.get_logical_device_agent(request.id)
212 agent.update_flow_table(request.flow_mod)
213 return Empty()
214 except KeyError:
215 context.set_details(
216 'Logical device \'{}\' not found'.format(request.id))
217 context.set_code(StatusCode.NOT_FOUND)
218 return Empty()
219
220 @twisted_async
221 def ListLogicalDeviceFlowGroups(self, request, context):
222 log.info('grpc-request', request=request)
223
224 if '/' in request.id:
225 context.set_details(
226 'Malformed logical device id \'{}\''.format(request.id))
227 context.set_code(StatusCode.INVALID_ARGUMENT)
228 return FlowGroups()
229
230 try:
231 groups = self.root.get(
232 '/logical_devices/{}/flow_groups'.format(request.id))
233 return groups
234 except KeyError:
235 context.set_details(
236 'Logical device \'{}\' not found'.format(request.id))
237 context.set_code(StatusCode.NOT_FOUND)
238 return FlowGroups()
239
240 @twisted_async
241 def UpdateLogicalDeviceFlowGroupTable(self, request, context):
242 log.info('grpc-request', request=request)
243
244 if '/' in request.id:
245 context.set_details(
246 'Malformed logical device id \'{}\''.format(request.id))
247 context.set_code(StatusCode.INVALID_ARGUMENT)
248 return Empty()
249
250 try:
251 agent = self.core.get_logical_device_agent(request.id)
252 agent.update_group_table(request.group_mod)
253 return Empty()
254 except KeyError:
255 context.set_details(
256 'Logical device \'{}\' not found'.format(request.id))
257 context.set_code(StatusCode.NOT_FOUND)
258 return Empty()
259
260 @twisted_async
261 def ListDevices(self, request, context):
262 log.info('grpc-request', request=request)
263 items = self.root.get('/devices')
264 return Devices(items=items)
265
266 @twisted_async
267 def GetDevice(self, request, context):
268 log.info('grpc-request', request=request)
269
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800270 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
271
Zsolt Haraszti66862032016-11-28 14:28:39 -0800272 if '/' in request.id:
273 context.set_details(
274 'Malformed device id \'{}\''.format(request.id))
275 context.set_code(StatusCode.INVALID_ARGUMENT)
276 return Device()
277
278 try:
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800279 return self.root.get('/devices/' + request.id, depth=depth)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800280 except KeyError:
281 context.set_details(
282 'Device \'{}\' not found'.format(request.id))
283 context.set_code(StatusCode.NOT_FOUND)
284 return Device()
285
286 @twisted_async
287 def CreateDevice(self, request, context):
288 log.info('grpc-request', request=request)
289
290 known_device_types = dict(
291 (dt.id, dt) for dt in self.root.get('/device_types'))
Nikolay Titovff35fb32017-09-24 13:33:29 -0400292 known_devices = self.root.get('/devices')
Zsolt Haraszti66862032016-11-28 14:28:39 -0800293
294 try:
295 assert isinstance(request, Device)
296 device = request
297 assert device.id == '', 'Device to be created cannot have id yet'
298 assert device.type in known_device_types, \
299 'Unknown device type \'{}\''.format(device.type)
300 assert device.admin_state in (AdminState.UNKNOWN,
301 AdminState.PREPROVISIONED), \
302 'Newly created device cannot be ' \
303 'in admin state \'{}\''.format(device.admin_state)
Nikolay Titovff35fb32017-09-24 13:33:29 -0400304 assert device.WhichOneof("address") is not None, \
305 'Device must have one contact address e.g. MAC, IPv4, IPv6, H&P'
306 error_message = 'Device with {} address \'{}\' already exists'
307 for _device in known_devices:
308 if _device.HasField(device.WhichOneof("address")):
309 if device.HasField("mac_address"):
310 assert device.mac_address != _device.mac_address, \
311 error_message.format('MAC', device.mac_address)
312 elif device.HasField("ipv4_address"):
313 assert device.ipv4_address != _device.ipv4_address, \
314 error_message.format('IPv4', device.ipv4_address)
315 elif device.HasField("ipv6_address"):
316 assert device.ipv6_address != _device.ipv6_address, \
317 error_message.format('IPv6', device.ipv6_address)
318 elif device.HasField("host_and_port"):
319 assert device.host_and_port != _device.host_and_port, \
320 error_message.format('Host and Port',
321 device.host_and_port)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800322 except AssertionError, e:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400323 context.set_details(e.message)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800324 context.set_code(StatusCode.INVALID_ARGUMENT)
325 return Device()
326
327 # fill additional data
khenaidooa8588f22017-06-16 12:13:34 -0400328 device.id = create_cluster_device_id(self.core_store_id)
329 log.debug('device-id-created', device_id=device.id)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800330 device_type = known_device_types[device.type]
331 device.adapter = device_type.adapter
332 if device.admin_state != AdminState.PREPROVISIONED:
333 device.admin_state = AdminState.PREPROVISIONED
334 device.oper_status = OperStatus.UNKNOWN
Niren R Chidrawara5753632017-08-31 03:18:03 -0400335 device.vendor_id = device_type.vendor_id
Zsolt Haraszti66862032016-11-28 14:28:39 -0800336
337 # add device to tree
338 self.root.add('/devices', device)
339
340 return request
341
342 @twisted_async
Khen Nursimulud068d812017-03-06 11:44:18 -0500343 def EnableDevice(self, request, context):
Zsolt Haraszti66862032016-11-28 14:28:39 -0800344 log.info('grpc-request', request=request)
345
346 if '/' in request.id:
347 context.set_details(
348 'Malformed device id \'{}\''.format(request.id))
349 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400350 return Empty()
Zsolt Haraszti66862032016-11-28 14:28:39 -0800351
352 try:
353 path = '/devices/{}'.format(request.id)
354 device = self.root.get(path)
Khen Nursimulud068d812017-03-06 11:44:18 -0500355 assert device.admin_state in (AdminState.PREPROVISIONED,
356 AdminState.DISABLED), \
357 'Device to enable cannot be ' \
358 'in admin state \'{}\''.format(device.admin_state)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800359 device.admin_state = AdminState.ENABLED
360 self.root.update(path, device, strict=True)
361
Khen Nursimulud068d812017-03-06 11:44:18 -0500362 except AssertionError, e:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400363 context.set_details(e.message)
Khen Nursimulud068d812017-03-06 11:44:18 -0500364 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimulud068d812017-03-06 11:44:18 -0500365
366 except KeyError:
367 context.set_details(
368 'Device \'{}\' not found'.format(request.id))
369 context.set_code(StatusCode.NOT_FOUND)
370
371 return Empty()
372
373 @twisted_async
374 def DisableDevice(self, request, context):
375 log.info('grpc-request', request=request)
376
377 if '/' in request.id:
378 context.set_details(
379 'Malformed device id \'{}\''.format(request.id))
380 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400381 return Empty()
Khen Nursimulud068d812017-03-06 11:44:18 -0500382 try:
383 path = '/devices/{}'.format(request.id)
384 device = self.root.get(path)
385 assert device.admin_state == AdminState.ENABLED, \
386 'Device to disable cannot be ' \
387 'in admin state \'{}\''.format(device.admin_state)
388 device.admin_state = AdminState.DISABLED
389 self.root.update(path, device, strict=True)
390
391 except AssertionError, e:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400392 context.set_details(e.message)
Khen Nursimulud068d812017-03-06 11:44:18 -0500393 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimulud068d812017-03-06 11:44:18 -0500394
395 except KeyError:
396 context.set_details(
397 'Device \'{}\' not found'.format(request.id))
398 context.set_code(StatusCode.NOT_FOUND)
399
khenaidoo032d3302017-06-09 14:50:04 -0400400 except Exception, e:
401 log.exception('disable-exception', e=e)
402
Khen Nursimulud068d812017-03-06 11:44:18 -0500403 return Empty()
404
405 @twisted_async
406 def RebootDevice(self, request, context):
407 log.info('grpc-request', request=request)
408
409 if '/' in request.id:
410 context.set_details(
411 'Malformed device id \'{}\''.format(request.id))
412 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400413 return Empty()
Khen Nursimulud068d812017-03-06 11:44:18 -0500414
415 try:
416 path = '/devices/{}'.format(request.id)
417 device = self.root.get(path)
Lydia Fang01f2e852017-06-28 17:24:58 -0700418 assert device.admin_state != AdminState.DOWNLOADING_IMAGE, \
419 'Device to reboot cannot be ' \
420 'in admin state \'{}\''.format(device.admin_state)
Khen Nursimulud068d812017-03-06 11:44:18 -0500421 agent = self.core.get_device_agent(device.id)
422 agent.reboot_device(device)
423
Khen Nursimulud068d812017-03-06 11:44:18 -0500424 except KeyError:
425 context.set_details(
426 'Device \'{}\' not found'.format(request.id))
427 context.set_code(StatusCode.NOT_FOUND)
428
429 return Empty()
430
431 @twisted_async
Lydia Fang01f2e852017-06-28 17:24:58 -0700432 def DownloadImage(self, request, context):
433 log.info('grpc-request', request=request)
434
435 if '/' in request.id:
436 context.set_details(
437 'Malformed device id \'{}\''.format(request.id))
438 context.set_code(StatusCode.INVALID_ARGUMENT)
439 return OperationResp(code=OperationResp.OPERATION_FAILURE)
440
441 try:
442 path = '/devices/{}'.format(request.id)
443 device = self.root.get(path)
444 assert isinstance(request, ImageDownload)
445 self.root.add('/devices/{}/image_downloads'.\
446 format(request.id), request)
447 assert device.admin_state == AdminState.ENABLED, \
448 'Device to DOWNLOADING_IMAGE cannot be ' \
449 'in admin state \'{}\''.format(device.admin_state)
450 device.admin_state = AdminState.DOWNLOADING_IMAGE
451 self.root.update(path, device, strict=True)
452 agent = self.core.get_device_agent(device.id)
453 agent.register_image_download(request)
454 return OperationResp(code=OperationResp.OPERATION_SUCCESS)
455
456 except AssertionError as e:
457 context.set_details(e.message)
458 context.set_code(StatusCode.INVALID_ARGUMENT)
459 return OperationResp(code=OperationResp.OPERATION_UNSUPPORTED)
460
461 except KeyError:
462 context.set_details(
463 'Device \'{}\' not found'.format(request.id))
464 context.set_code(StatusCode.NOT_FOUND)
465 return OperationResp(code=OperationResp.OPERATION_FAILURE)
466
467 except Exception as e:
468 log.exception(e.message)
469 context.set_code(StatusCode.NOT_FOUND)
470 return OperationResp(code=OperationResp.OPERATION_FAILURE)
471
472 @twisted_async
473 def GetImageDownloadStatus(self, request, context):
474 log.info('grpc-request', request=request)
475
476 if '/' in request.id:
477 context.set_details(
478 'Malformed device id \'{}\''.format(request.id))
479 context.set_code(StatusCode.INVALID_ARGUMENT)
480 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
481 return response
482
483 try:
484 path = '/devices/{}'.format(request.id)
485 device = self.root.get(path)
486 agent = self.core.get_device_agent(device.id)
487 img_dnld = self.root.get('/devices/{}/image_downloads/{}'.\
488 format(request.id, request.name))
489 agent.get_image_download_status(img_dnld)
490 try:
491 response = self.root.get('/devices/{}/image_downloads/{}'.\
492 format(request.id, request.name))
493 except Exception as e:
494 log.exception(e.message)
495 return response
496
497 except KeyError:
498 context.set_details(
499 'Device \'{}\' not found'.format(request.id))
500 context.set_code(StatusCode.NOT_FOUND)
501 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
502 return response
503 except Exception as e:
504 log.exception(e.message)
505 response = ImageDownload(state=ImageDownload.DOWNLOAD_FAILED)
506 return response
507
508 @twisted_async
509 def GetImageDownload(self, request, context):
510 log.info('grpc-request', request=request)
511
512 if '/' in request.id:
513 context.set_details(
514 'Malformed device id \'{}\''.format(request.id))
515 context.set_code(StatusCode.INVALID_ARGUMENT)
516 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
517 return response
518
519 try:
520 response = self.root.get('/devices/{}/image_downloads/{}'.\
521 format(request.id, request.name))
522 return response
523
524 except KeyError:
525 context.set_details(
526 'Device \'{}\' not found'.format(request.id))
527 context.set_code(StatusCode.NOT_FOUND)
528 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
529 return response
530
531 @twisted_async
532 def ListImageDownloads(self, request, context):
533 log.info('grpc-request', request=request)
534
535 if '/' in request.id:
536 context.set_details(
537 'Malformed device id \'{}\''.format(request.id))
538 context.set_code(StatusCode.INVALID_ARGUMENT)
539 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
540 return response
541
542 try:
543 response = self.root.get('/devices/{}/image_downloads'.\
544 format(request.id))
545 return ImageDownloads(items=response)
546
547 except KeyError:
548 context.set_details(
549 'Device \'{}\' not found'.format(request.id))
550 context.set_code(StatusCode.NOT_FOUND)
551 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
552 return response
553
554 @twisted_async
555 def CancelImageDownload(self, request, context):
556 log.info('grpc-request', request=request)
557
558 if '/' in request.id:
559 context.set_details(
560 'Malformed device id \'{}\''.format(request.id))
561 context.set_code(StatusCode.INVALID_ARGUMENT)
562 return OperationResp(code=OperationResp.OPERATION_FAILURE)
563
564 try:
565 assert isinstance(request, ImageDownload)
566 path = '/devices/{}'.format(request.id)
567 device = self.root.get(path)
568 assert device.admin_state == AdminState.DOWNLOADING_IMAGE, \
569 'Device to cancel DOWNLOADING_IMAGE cannot be ' \
570 'in admin state \'{}\''.format(device.admin_state)
571 agent = self.core.get_device_agent(device.id)
572 agent.cancel_image_download(request)
573 return OperationResp(code=OperationResp.OPERATION_SUCCESS)
574
575 except KeyError:
576 context.set_details(
577 'Device \'{}\' not found'.format(request.id))
578 context.set_code(StatusCode.NOT_FOUND)
579 return OperationResp(code=OperationResp.OPERATION_FAILURE)
580
581 @twisted_async
582 def ActivateImageUpdate(self, request, context):
583 log.info('grpc-request', request=request)
584
585 if '/' in request.id:
586 context.set_details(
587 'Malformed device id \'{}\''.format(request.id))
588 context.set_code(StatusCode.INVALID_ARGUMENT)
589 return OperationResp(code=OperationResp.OPERATION_FAILURE)
590
591 try:
592 assert isinstance(request, ImageDownload)
593 path = '/devices/{}'.format(request.id)
594 device = self.root.get(path)
595 assert device.admin_state == AdminState.ENABLED, \
596 'Device to activate image cannot be ' \
597 'in admin state \'{}\''.format(device.admin_state)
598 agent = self.core.get_device_agent(device.id)
599 agent.activate_image_update(request)
600 return OperationResp(code=OperationResp.OPERATION_SUCCESS)
601
602 except KeyError:
603 context.set_details(
604 'Device \'{}\' not found'.format(request.id))
605 context.set_code(StatusCode.NOT_FOUND)
606 return OperationResp(code=OperationResp.OPERATION_FAILURE)
607
608 @twisted_async
609 def RevertImageUpdate(self, request, context):
610 log.info('grpc-request', request=request)
611
612 if '/' in request.id:
613 context.set_details(
614 'Malformed device id \'{}\''.format(request.id))
615 context.set_code(StatusCode.INVALID_ARGUMENT)
616 return OperationResp(code=OperationResp.OPERATION_FAILURE)
617
618 try:
619 assert isinstance(request, ImageDownload)
620 path = '/devices/{}'.format(request.id)
621 device = self.root.get(path)
622 assert device.admin_state == AdminState.ENABLED, \
623 'Device to revert image cannot be ' \
624 'in admin state \'{}\''.format(device.admin_state)
625 agent = self.core.get_device_agent(device.id)
626 agent.revert_image_update(request)
627 return OperationResp(code=OperationResp.OPERATION_SUCCESS)
628
629 except KeyError:
630 context.set_details(
631 'Device \'{}\' not found'.format(request.id))
632 context.set_code(StatusCode.NOT_FOUND)
633 return OperationResp(code=OperationResp.OPERATION_FAILURE)
634
635 @twisted_async
Khen Nursimulud068d812017-03-06 11:44:18 -0500636 def DeleteDevice(self, request, context):
637 log.info('grpc-request', request=request)
638
639 if '/' in request.id:
640 context.set_details(
641 'Malformed device id \'{}\''.format(request.id))
642 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400643 return Empty()
Khen Nursimulud068d812017-03-06 11:44:18 -0500644
645 try:
646 path = '/devices/{}'.format(request.id)
647 device = self.root.get(path)
648 assert device.admin_state == AdminState.DISABLED, \
649 'Device to delete cannot be ' \
650 'in admin state \'{}\''.format(device.admin_state)
Nikolay Titov6a485582017-10-06 00:18:36 -0400651 assert not device.type.endswith("_onu"), \
652 'ONU device cannot be deleted. ' \
653 'Please consider deleting VOntAni to delete ONU device.'
Khen Nursimulud068d812017-03-06 11:44:18 -0500654
655 self.root.remove(path)
656
657 except AssertionError, e:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400658 context.set_details(e.message)
Khen Nursimulud068d812017-03-06 11:44:18 -0500659 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimulud068d812017-03-06 11:44:18 -0500660
Zsolt Haraszti66862032016-11-28 14:28:39 -0800661 except KeyError:
662 context.set_details(
663 'Device \'{}\' not found'.format(request.id))
664 context.set_code(StatusCode.NOT_FOUND)
665
666 return Empty()
667
668 @twisted_async
669 def ListDevicePorts(self, request, context):
670 log.info('grpc-request', request=request)
671
672 if '/' in request.id:
673 context.set_details(
674 'Malformed device id \'{}\''.format(request.id))
675 context.set_code(StatusCode.INVALID_ARGUMENT)
676 return Ports()
677
678 try:
679 items = self.root.get('/devices/{}/ports'.format(request.id))
680 return Ports(items=items)
681 except KeyError:
682 context.set_details(
683 'Device \'{}\' not found'.format(request.id))
684 context.set_code(StatusCode.NOT_FOUND)
685 return Ports()
686
Sergio Slobodriana2eb52b2017-03-07 12:24:46 -0500687 @twisted_async
688 def ListDevicePmConfigs(self, request, context):
Sergio Slobodrian71960022017-03-09 10:20:57 -0500689 log.info('grpc-request', request=request)
Sergio Slobodriana2eb52b2017-03-07 12:24:46 -0500690
Sergio Slobodrian71960022017-03-09 10:20:57 -0500691 if '/' in request.id:
692 context.set_details(
693 'Malformed device id \'{}\''.format(request.id))
694 context.set_code(StatusCode.INVALID_ARGUMENT)
695 return PmConfigs()
696
697 try:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400698 pm_configs = self.root.get(
699 '/devices/{}/pm_configs'.format(request.id))
Sergio Slobodrian2db4c102017-03-09 22:29:23 -0500700 pm_configs.id = request.id
khenaidoo5431e4c2017-08-17 15:05:40 -0400701 log.debug('device-for-pms', pm_configs=pm_configs)
Sergio Slobodrian2db4c102017-03-09 22:29:23 -0500702 return pm_configs
Sergio Slobodrian71960022017-03-09 10:20:57 -0500703 except KeyError:
704 context.set_details(
705 'Device \'{}\' not found'.format(request.id))
706 context.set_code(StatusCode.NOT_FOUND)
707 return PmConfigs()
708
Sergio Slobodriana2eb52b2017-03-07 12:24:46 -0500709 @twisted_async
710 def UpdateDevicePmConfigs(self, request, context):
khenaidoo5431e4c2017-08-17 15:05:40 -0400711 log.debug('grpc-request', request=request)
Sergio Slobodrian2db4c102017-03-09 22:29:23 -0500712
713 if '/' in request.id:
714 context.set_details(
715 'Malformed logical device id \'{}\''.format(request.id))
716 context.set_code(StatusCode.INVALID_ARGUMENT)
717 return Empty()
718
719 try:
720 device = self.root.get('/devices/{}'.format(request.id))
721 agent = self.core.get_device_agent(request.id)
722 agent.update_device_pm_config(request)
723 return Empty()
724 except KeyError:
725 context.set_details(
726 'Device \'{}\' not found'.format(request.id))
727 context.set_code(StatusCode.NOT_FOUND)
728 return Empty()
Sergio Slobodriana2eb52b2017-03-07 12:24:46 -0500729
Zsolt Haraszti66862032016-11-28 14:28:39 -0800730 @twisted_async
731 def ListDeviceFlows(self, request, context):
732 log.info('grpc-request', request=request)
733
734 if '/' in request.id:
735 context.set_details(
736 'Malformed device id \'{}\''.format(request.id))
737 context.set_code(StatusCode.INVALID_ARGUMENT)
738 return Flows()
739
740 try:
741 flows = self.root.get('/devices/{}/flows'.format(request.id))
742 return flows
743 except KeyError:
744 context.set_details(
745 'Device \'{}\' not found'.format(request.id))
746 context.set_code(StatusCode.NOT_FOUND)
747 return Flows()
748
Zsolt Haraszti66862032016-11-28 14:28:39 -0800749 @twisted_async
750 def ListDeviceFlowGroups(self, request, context):
751 log.info('grpc-request', request=request)
752
753 if '/' in request.id:
754 context.set_details(
755 'Malformed device id \'{}\''.format(request.id))
756 context.set_code(StatusCode.INVALID_ARGUMENT)
757 return FlowGroups()
758
759 try:
Khen Nursimulud068d812017-03-06 11:44:18 -0500760 groups = self.root.get(
761 '/devices/{}/flow_groups'.format(request.id))
Zsolt Haraszti66862032016-11-28 14:28:39 -0800762 return groups
763 except KeyError:
764 context.set_details(
765 'Device \'{}\' not found'.format(request.id))
766 context.set_code(StatusCode.NOT_FOUND)
767 return FlowGroups()
768
769 @twisted_async
770 def ListDeviceTypes(self, request, context):
771 log.info('grpc-request', request=request)
772 items = self.root.get('/device_types')
khenaidooc4832162017-09-20 11:55:04 -0400773 sorted_items = sorted(items, key=lambda i: i.id)
774 return DeviceTypes(items=sorted_items)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800775
776 @twisted_async
777 def GetDeviceType(self, request, context):
778 log.info('grpc-request', request=request)
779
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800780 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
781
Zsolt Haraszti66862032016-11-28 14:28:39 -0800782 if '/' in request.id:
783 context.set_details(
784 'Malformed device type id \'{}\''.format(request.id))
785 context.set_code(StatusCode.INVALID_ARGUMENT)
786 return DeviceType()
787
788 try:
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800789 return self.root.get('/device_types/' + request.id, depth=depth)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800790 except KeyError:
791 context.set_details(
792 'Device type \'{}\' not found'.format(request.id))
793 context.set_code(StatusCode.NOT_FOUND)
794 return DeviceType()
795
796 @twisted_async
797 def ListDeviceGroups(self, request, context):
798 log.info('grpc-request', request=request)
799 # TODO is this mapped to tree or taken from coordinator?
800 items = self.root.get('/device_groups')
801 return DeviceGroups(items=items)
802
803 @twisted_async
804 def GetDeviceGroup(self, request, context):
805 log.info('grpc-request', request=request)
806
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800807 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
808
Zsolt Haraszti66862032016-11-28 14:28:39 -0800809 if '/' in request.id:
810 context.set_details(
811 'Malformed device group id \'{}\''.format(request.id))
812 context.set_code(StatusCode.INVALID_ARGUMENT)
813 return DeviceGroup()
814
815 # TODO is this mapped to tree or taken from coordinator?
816 try:
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800817 return self.root.get('/device_groups/' + request.id, depth=depth)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800818 except KeyError:
819 context.set_details(
820 'Device group \'{}\' not found'.format(request.id))
821 context.set_code(StatusCode.NOT_FOUND)
822 return DeviceGroup()
823
Nikolay Titov89004ec2017-06-19 18:22:42 -0400824 # bbf_fiber rpcs start
825 @twisted_async
826 def GetAllChannelgroupConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400827 return self.core.xpon_handler.get_all_channel_group_config(
828 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400829
830 @twisted_async
831 def CreateChannelgroup(self, request, context):
832 return self.core.xpon_handler.create_channel_group(request, context)
833
834 @twisted_async
835 def UpdateChannelgroup(self, request, context):
836 return self.core.xpon_handler.update_channel_group(request, context)
837
838 @twisted_async
839 def DeleteChannelgroup(self, request, context):
840 return self.core.xpon_handler.delete_channel_group(request, context)
841
842 @twisted_async
843 def GetAllChannelpartitionConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400844 return self.core.xpon_handler.get_all_channel_partition_config(
845 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400846
847 @twisted_async
848 def CreateChannelpartition(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400849 return self.core.xpon_handler.create_channel_partition(
850 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400851
852 @twisted_async
853 def UpdateChannelpartition(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400854 return self.core.xpon_handler.update_channel_partition(
855 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400856
857 @twisted_async
858 def DeleteChannelpartition(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400859 return self.core.xpon_handler.delete_channel_partition(
860 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400861
862 @twisted_async
863 def GetAllChannelpairConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400864 return self.core.xpon_handler.get_all_channel_pair_config(
865 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400866
867 @twisted_async
868 def CreateChannelpair(self, request, context):
869 return self.core.xpon_handler.create_channel_pair(request, context)
870
871 @twisted_async
872 def UpdateChannelpair(self, request, context):
873 return self.core.xpon_handler.update_channel_pair(request, context)
874
875 @twisted_async
876 def DeleteChannelpair(self, request, context):
877 return self.core.xpon_handler.delete_channel_pair(request, context)
878
879 @twisted_async
880 def GetAllChannelterminationConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400881 return self.core.xpon_handler.get_all_channel_termination_config(
882 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400883
884 @twisted_async
885 def CreateChanneltermination(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400886 return self.core.xpon_handler.create_channel_termination(
887 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400888
889 @twisted_async
890 def UpdateChanneltermination(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400891 return self.core.xpon_handler.update_channel_termination(
892 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400893
894 @twisted_async
895 def DeleteChanneltermination(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400896 return self.core.xpon_handler.delete_channel_termination(
897 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400898
899 @twisted_async
900 def GetAllOntaniConfig(self, request, context):
901 return self.core.xpon_handler.get_all_ont_ani_config(request, context)
902
903 @twisted_async
904 def CreateOntani(self, request, context):
905 return self.core.xpon_handler.create_ont_ani(request, context)
906
907 @twisted_async
908 def UpdateOntani(self, request, context):
909 return self.core.xpon_handler.update_ont_ani(request, context)
910
911 @twisted_async
912 def DeleteOntani(self, request, context):
913 return self.core.xpon_handler.delete_ont_ani(request, context)
914
915 @twisted_async
916 def GetAllVOntaniConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400917 return self.core.xpon_handler.get_all_v_ont_ani_config(
918 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400919
920 @twisted_async
921 def CreateVOntani(self, request, context):
922 return self.core.xpon_handler.create_v_ont_ani(request, context)
923
924 @twisted_async
925 def UpdateVOntani(self, request, context):
926 return self.core.xpon_handler.update_v_ont_ani(request, context)
927
928 @twisted_async
929 def DeleteVOntani(self, request, context):
930 return self.core.xpon_handler.delete_v_ont_ani(request, context)
931
932 @twisted_async
933 def GetAllVEnetConfig(self, request, context):
934 return self.core.xpon_handler.get_all_v_enet_config(request, context)
935
936 @twisted_async
937 def CreateVEnet(self, request, context):
938 return self.core.xpon_handler.create_v_enet(request, context)
939
940 @twisted_async
941 def UpdateVEnet(self, request, context):
942 return self.core.xpon_handler.update_v_enet(request, context)
943
944 @twisted_async
945 def DeleteVEnet(self, request, context):
946 return self.core.xpon_handler.delete_v_enet(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400947
948 @twisted_async
949 def GetAllTrafficDescriptorProfileData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400950 return self.core.xpon_handler.get_all_traffic_descriptor_profile_data(
951 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400952
953 @twisted_async
954 def CreateTrafficDescriptorProfileData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400955 return self.core.xpon_handler.create_traffic_descriptor_profile(
956 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400957
958 @twisted_async
959 def UpdateTrafficDescriptorProfileData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400960 return self.core.xpon_handler.update_traffic_descriptor_profile(
961 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400962
963 @twisted_async
964 def DeleteTrafficDescriptorProfileData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400965 return self.core.xpon_handler.delete_traffic_descriptor_profile(
966 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400967
968 @twisted_async
969 def GetAllTcontsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400970 return self.core.xpon_handler.get_all_tconts_config_data(
971 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400972
973 @twisted_async
974 def CreateTcontsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400975 return self.core.xpon_handler.create_tcont(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400976
977 @twisted_async
978 def UpdateTcontsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400979 return self.core.xpon_handler.update_tcont(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400980
981 @twisted_async
982 def DeleteTcontsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400983 return self.core.xpon_handler.delete_tcont(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400984
985 @twisted_async
986 def GetAllGemportsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400987 return self.core.xpon_handler.get_all_gemports_config_data(
988 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400989
990 @twisted_async
991 def CreateGemportsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400992 return self.core.xpon_handler.create_gem_port(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400993
994 @twisted_async
995 def UpdateGemportsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400996 return self.core.xpon_handler.update_gem_port(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400997
998 @twisted_async
999 def DeleteGemportsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001000 return self.core.xpon_handler.delete_gem_port(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001001
1002 @twisted_async
1003 def GetAllMulticastGemportsConfigData(self, request, context):
1004 return AllMulticastGemportsConfigData()
1005
1006 @twisted_async
1007 def CreateMulticastGemportsConfigData(self, request, context):
1008 return Empty()
1009
1010 @twisted_async
1011 def UpdateMulticastGemportsConfigData(self, request, context):
1012 return Empty()
1013
1014 @twisted_async
1015 def DeleteMulticastGemportsConfigData(self, request, context):
1016 return Empty()
1017
1018 @twisted_async
1019 def GetAllMulticastDistributionSetData(self, request, context):
1020 return AllMulticastDistributionSetData()
1021
1022 @twisted_async
1023 def CreateMulticastDistributionSetData(self, request, context):
1024 return Empty()
1025
1026 @twisted_async
1027 def UpdateMulticastDistributionSetData(self, request, context):
1028 return Empty()
1029
1030 @twisted_async
1031 def DeleteMulticastDistributionSetData(self, request, context):
1032 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -04001033 # bbf_fiber rpcs end
1034
Zsolt Haraszti66862032016-11-28 14:28:39 -08001035 def StreamPacketsOut(self, request_iterator, context):
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001036 log.debug('start-stream-packets-out')
Zsolt Haraszti66862032016-11-28 14:28:39 -08001037
1038 @twisted_async
1039 def forward_packet_out(packet_out):
1040 agent = self.core.get_logical_device_agent(packet_out.id)
1041 agent.packet_out(packet_out.packet_out)
1042
1043 for request in request_iterator:
1044 forward_packet_out(packet_out=request)
1045
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001046 log.debug('stop-stream-packets-out')
1047
Zsolt Haraszti66862032016-11-28 14:28:39 -08001048 return Empty()
1049
1050 def ReceivePacketsIn(self, request, context):
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001051 log.debug('start-receive-packets-in')
1052 while self.ofagent_is_alive:
Zsolt Haraszti3300f742017-01-09 01:14:20 -08001053 try:
1054 packet_in = self.core.packet_in_queue.get(timeout=1)
1055 yield packet_in
1056 except QueueEmpty:
1057 if self.stopped:
1058 break
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001059 log.debug('stop-receive-packets-in')
Zsolt Haraszti66862032016-11-28 14:28:39 -08001060
1061 def send_packet_in(self, device_id, ofp_packet_in):
1062 """Must be called on the twisted thread"""
1063 packet_in = PacketIn(id=device_id, packet_in=ofp_packet_in)
1064 self.core.packet_in_queue.put(packet_in)
Zsolt Haraszti217a12e2016-12-19 16:37:55 -08001065
1066 def ReceiveChangeEvents(self, request, context):
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001067 log.debug('start-receive-change-events')
1068 while self.ofagent_is_alive:
Zsolt Haraszti3300f742017-01-09 01:14:20 -08001069 try:
1070 event = self.core.change_event_queue.get(timeout=1)
1071 yield event
1072 except QueueEmpty:
1073 if self.stopped:
1074 break
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001075 log.debug('stop-receive-change-events')
Zsolt Haraszti217a12e2016-12-19 16:37:55 -08001076
1077 def send_port_change_event(self, device_id, port_status):
1078 """Must be called on the twisted thread"""
1079 assert isinstance(port_status, ofp_port_status)
1080 event = ChangeEvent(id=device_id, port_status=port_status)
1081 self.core.change_event_queue.put(event)
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001082
1083
1084 @twisted_async
1085 def ListAlarmFilters(self, request, context):
1086 try:
1087 filters = self.root.get('/alarm_filters')
1088 return AlarmFilters(filters=filters)
1089 except KeyError:
1090 context.set_code(StatusCode.NOT_FOUND)
1091 return AlarmFilters()
1092
1093 @twisted_async
1094 def GetAlarmFilter(self, request, context):
1095 if '/' in request.id:
1096 context.set_details(
1097 'Malformed alarm filter id \'{}\''.format(request.id))
1098 context.set_code(StatusCode.INVALID_ARGUMENT)
1099 return AlarmFilter()
1100
1101 try:
1102 alarm_filter = self.root.get('/alarm_filters/{}'.format(request.id))
khenaidoo08d48d22017-06-29 19:42:49 -04001103
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001104 return alarm_filter
1105 except KeyError:
1106 context.set_details(
1107 'Alarm filter \'{}\' not found'.format(request.id))
1108 context.set_code(StatusCode.NOT_FOUND)
1109 return AlarmFilter()
1110
1111 @twisted_async
1112 def DeleteAlarmFilter(self, request, context):
1113 if '/' in request.id:
1114 context.set_details(
1115 'Malformed alarm filter id \'{}\''.format(request.id))
1116 context.set_code(StatusCode.INVALID_ARGUMENT)
1117 return Empty()
1118
1119 try:
1120 self.root.remove('/alarm_filters/{}'.format(request.id))
1121 except KeyError:
1122 context.set_code(StatusCode.NOT_FOUND)
1123
1124 return Empty()
1125
1126 @twisted_async
1127 def CreateAlarmFilter(self, request, context):
1128 log.info('grpc-request', request=request)
1129
1130 try:
1131 assert isinstance(request, AlarmFilter)
1132 alarm_filter = request
khenaidoo08d48d22017-06-29 19:42:49 -04001133 assert alarm_filter.id is not None, 'Local Alarm filter to be ' \
1134 'created must have id'
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001135 except AssertionError, e:
1136 context.set_details(e.message)
1137 context.set_code(StatusCode.INVALID_ARGUMENT)
1138 return AlarmFilter()
1139
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001140 # add device to tree
1141 self.root.add('/alarm_filters', alarm_filter)
1142
1143 return request
1144
1145 @twisted_async
1146 def UpdateAlarmFilter(self, request, context):
1147 if '/' in request.id:
1148 context.set_details(
1149 'Malformed alarm filter id \'{}\''.format(request.id))
1150 context.set_code(StatusCode.INVALID_ARGUMENT)
1151 return AlarmFilter()
1152
1153 try:
1154 assert isinstance(request, AlarmFilter)
1155 alarm_filter = self.root.get('/alarm_filters/{}'.format(request.id))
1156 self.root.update('/alarm_filters/{}'.format(request.id), request)
1157
1158 return request
1159 except KeyError:
1160 context.set_details(
1161 'Alarm filter \'{}\' not found'.format(request.id))
1162 context.set_code(StatusCode.NOT_FOUND)
1163 return AlarmFilter()
ggowdru236bd952017-06-20 20:32:55 -07001164
1165 @twisted_async
1166 def GetImages(self, request, context):
1167 log.info('grpc-request', request=request)
1168
1169 if '/' in request.id:
1170 context.set_details(
1171 'Malformed device id \'{}\''.format(request.id))
1172 context.set_code(StatusCode.INVALID_ARGUMENT)
1173 return Images()
1174
1175 try:
1176 device = self.root.get('/devices/' + request.id)
1177 return device.images
1178
1179 except KeyError:
1180 context.set_details(
1181 'Device \'{}\' not found'.format(request.id))
1182 context.set_code(StatusCode.NOT_FOUND)
1183 return Images()
sathishg5ae86222017-06-28 15:16:29 +05301184
1185 @twisted_async
1186 def SelfTest(self, request, context):
1187 log.info('grpc-request', request=request)
1188
1189 if '/' in request.id:
1190 context.set_details(
1191 'Malformed device id \'{}\''.format(request.id))
1192 context.set_code(StatusCode.INVALID_ARGUMENT)
1193 return SelfTestResponse()
1194
1195 try:
1196 path = '/devices/{}'.format(request.id)
1197 device = self.root.get(path)
1198
1199 agent = self.core.get_device_agent(device.id)
1200 resp = agent.self_test(device)
1201 return resp.result
1202
1203 except KeyError:
1204 context.set_details(
1205 'Device \'{}\' not found'.format(request.id))
1206 context.set_code(StatusCode.NOT_FOUND)
1207 return SelfTestResponse()
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001208
1209 def _ofagent_session_termination(self):
1210 log.debug('start-ofagent-session-termination')
1211
1212 # Stop ofagent heartbeat
1213 if self.ofagent_heartbeat_lc is not None:
1214 self.ofagent_heartbeat_lc.stop()
1215
1216 # Reset flags and assignments
1217 self.ofagent_is_alive = False
1218 self.subscriber = None
1219 self.ofagent_heartbeat_count = 0
1220
1221 # Some local services will stop (packet-in/change-events)
1222 # need to re-register them
1223 registry('grpc_server').register(
1224 add_VolthaLocalServiceServicer_to_server, self)
1225
1226 log.debug('stop-ofagent-session-termination')
1227
1228 def _ofagent_session_heartbeat(self):
1229 log.debug('start-ofagent-heartbeat')
1230 if self.ofagent_heartbeat_count > self.ofagent_heartbeat_max_count:
1231 self._ofagent_session_termination()
1232 else:
1233 self.ofagent_heartbeat_count += 1
1234
1235 log.debug('stop-ofagent-heartbeat')
1236
1237 @twisted_async
1238 def Subscribe(self, request, context):
1239 log.info('grpc-request', request=request)
1240
1241 # Check if an ofagent subscriber is assigned
1242 if self.subscriber is None:
1243 log.debug('ofagent-subscriber-request')
1244
1245 try:
1246 # Assign the request as the active subscriber
1247 self.subscriber = OfAgentSubscriber(
1248 ofagent_id=request.ofagent_id,
1249 voltha_id=self.instance_id
1250 )
1251
1252 # Start the hearbeat
1253 self.ofagent_heartbeat_count = 0
1254 self.ofagent_heartbeat_lc = task.LoopingCall(self._ofagent_session_heartbeat)
1255 self.ofagent_heartbeat_lc.start(self.ofagent_heartbeat_delay)
1256
1257 log.debug('ofagent-subscriber-connected', subscriber=self.subscriber)
1258
1259 except _Rendezvous, e:
1260 log.error('ofagent-subscriber-failure', exception=repr(e), status=e.code())
1261
1262 except Exception as e:
1263 log.exception('ofagent-subscriber-unexpected-failure', exception=repr(e))
1264
1265 elif self.subscriber.ofagent_id == request.ofagent_id:
1266 log.debug('ofagent-subscriber-matches-assigned',
1267 current=self.subscriber)
1268 # reset counter
1269 self.ofagent_heartbeat_count = 0
1270
1271 else:
1272 log.debug('ofagent-subscriber-not-matching-assigned',
1273 current=self.subscriber)
1274
1275 return self.subscriber