blob: 70f3ecdff523031235fc2105550e51db7dfcaf09 [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)
651
652 self.root.remove(path)
653
654 except AssertionError, e:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400655 context.set_details(e.message)
Khen Nursimulud068d812017-03-06 11:44:18 -0500656 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimulud068d812017-03-06 11:44:18 -0500657
Zsolt Haraszti66862032016-11-28 14:28:39 -0800658 except KeyError:
659 context.set_details(
660 'Device \'{}\' not found'.format(request.id))
661 context.set_code(StatusCode.NOT_FOUND)
662
663 return Empty()
664
665 @twisted_async
666 def ListDevicePorts(self, request, context):
667 log.info('grpc-request', request=request)
668
669 if '/' in request.id:
670 context.set_details(
671 'Malformed device id \'{}\''.format(request.id))
672 context.set_code(StatusCode.INVALID_ARGUMENT)
673 return Ports()
674
675 try:
676 items = self.root.get('/devices/{}/ports'.format(request.id))
677 return Ports(items=items)
678 except KeyError:
679 context.set_details(
680 'Device \'{}\' not found'.format(request.id))
681 context.set_code(StatusCode.NOT_FOUND)
682 return Ports()
683
Sergio Slobodriana2eb52b2017-03-07 12:24:46 -0500684 @twisted_async
685 def ListDevicePmConfigs(self, request, context):
Sergio Slobodrian71960022017-03-09 10:20:57 -0500686 log.info('grpc-request', request=request)
Sergio Slobodriana2eb52b2017-03-07 12:24:46 -0500687
Sergio Slobodrian71960022017-03-09 10:20:57 -0500688 if '/' in request.id:
689 context.set_details(
690 'Malformed device id \'{}\''.format(request.id))
691 context.set_code(StatusCode.INVALID_ARGUMENT)
692 return PmConfigs()
693
694 try:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400695 pm_configs = self.root.get(
696 '/devices/{}/pm_configs'.format(request.id))
Sergio Slobodrian2db4c102017-03-09 22:29:23 -0500697 pm_configs.id = request.id
khenaidoo5431e4c2017-08-17 15:05:40 -0400698 log.debug('device-for-pms', pm_configs=pm_configs)
Sergio Slobodrian2db4c102017-03-09 22:29:23 -0500699 return pm_configs
Sergio Slobodrian71960022017-03-09 10:20:57 -0500700 except KeyError:
701 context.set_details(
702 'Device \'{}\' not found'.format(request.id))
703 context.set_code(StatusCode.NOT_FOUND)
704 return PmConfigs()
705
Sergio Slobodriana2eb52b2017-03-07 12:24:46 -0500706 @twisted_async
707 def UpdateDevicePmConfigs(self, request, context):
khenaidoo5431e4c2017-08-17 15:05:40 -0400708 log.debug('grpc-request', request=request)
Sergio Slobodrian2db4c102017-03-09 22:29:23 -0500709
710 if '/' in request.id:
711 context.set_details(
712 'Malformed logical device id \'{}\''.format(request.id))
713 context.set_code(StatusCode.INVALID_ARGUMENT)
714 return Empty()
715
716 try:
717 device = self.root.get('/devices/{}'.format(request.id))
718 agent = self.core.get_device_agent(request.id)
719 agent.update_device_pm_config(request)
720 return Empty()
721 except KeyError:
722 context.set_details(
723 'Device \'{}\' not found'.format(request.id))
724 context.set_code(StatusCode.NOT_FOUND)
725 return Empty()
Sergio Slobodriana2eb52b2017-03-07 12:24:46 -0500726
Zsolt Haraszti66862032016-11-28 14:28:39 -0800727 @twisted_async
728 def ListDeviceFlows(self, request, context):
729 log.info('grpc-request', request=request)
730
731 if '/' in request.id:
732 context.set_details(
733 'Malformed device id \'{}\''.format(request.id))
734 context.set_code(StatusCode.INVALID_ARGUMENT)
735 return Flows()
736
737 try:
738 flows = self.root.get('/devices/{}/flows'.format(request.id))
739 return flows
740 except KeyError:
741 context.set_details(
742 'Device \'{}\' not found'.format(request.id))
743 context.set_code(StatusCode.NOT_FOUND)
744 return Flows()
745
Zsolt Haraszti66862032016-11-28 14:28:39 -0800746 @twisted_async
747 def ListDeviceFlowGroups(self, request, context):
748 log.info('grpc-request', request=request)
749
750 if '/' in request.id:
751 context.set_details(
752 'Malformed device id \'{}\''.format(request.id))
753 context.set_code(StatusCode.INVALID_ARGUMENT)
754 return FlowGroups()
755
756 try:
Khen Nursimulud068d812017-03-06 11:44:18 -0500757 groups = self.root.get(
758 '/devices/{}/flow_groups'.format(request.id))
Zsolt Haraszti66862032016-11-28 14:28:39 -0800759 return groups
760 except KeyError:
761 context.set_details(
762 'Device \'{}\' not found'.format(request.id))
763 context.set_code(StatusCode.NOT_FOUND)
764 return FlowGroups()
765
766 @twisted_async
767 def ListDeviceTypes(self, request, context):
768 log.info('grpc-request', request=request)
769 items = self.root.get('/device_types')
khenaidooc4832162017-09-20 11:55:04 -0400770 sorted_items = sorted(items, key=lambda i: i.id)
771 return DeviceTypes(items=sorted_items)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800772
773 @twisted_async
774 def GetDeviceType(self, request, context):
775 log.info('grpc-request', request=request)
776
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800777 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
778
Zsolt Haraszti66862032016-11-28 14:28:39 -0800779 if '/' in request.id:
780 context.set_details(
781 'Malformed device type id \'{}\''.format(request.id))
782 context.set_code(StatusCode.INVALID_ARGUMENT)
783 return DeviceType()
784
785 try:
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800786 return self.root.get('/device_types/' + request.id, depth=depth)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800787 except KeyError:
788 context.set_details(
789 'Device type \'{}\' not found'.format(request.id))
790 context.set_code(StatusCode.NOT_FOUND)
791 return DeviceType()
792
793 @twisted_async
794 def ListDeviceGroups(self, request, context):
795 log.info('grpc-request', request=request)
796 # TODO is this mapped to tree or taken from coordinator?
797 items = self.root.get('/device_groups')
798 return DeviceGroups(items=items)
799
800 @twisted_async
801 def GetDeviceGroup(self, request, context):
802 log.info('grpc-request', request=request)
803
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800804 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
805
Zsolt Haraszti66862032016-11-28 14:28:39 -0800806 if '/' in request.id:
807 context.set_details(
808 'Malformed device group id \'{}\''.format(request.id))
809 context.set_code(StatusCode.INVALID_ARGUMENT)
810 return DeviceGroup()
811
812 # TODO is this mapped to tree or taken from coordinator?
813 try:
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800814 return self.root.get('/device_groups/' + request.id, depth=depth)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800815 except KeyError:
816 context.set_details(
817 'Device group \'{}\' not found'.format(request.id))
818 context.set_code(StatusCode.NOT_FOUND)
819 return DeviceGroup()
820
Nikolay Titov89004ec2017-06-19 18:22:42 -0400821 # bbf_fiber rpcs start
822 @twisted_async
823 def GetAllChannelgroupConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400824 return self.core.xpon_handler.get_all_channel_group_config(
825 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400826
827 @twisted_async
828 def CreateChannelgroup(self, request, context):
829 return self.core.xpon_handler.create_channel_group(request, context)
830
831 @twisted_async
832 def UpdateChannelgroup(self, request, context):
833 return self.core.xpon_handler.update_channel_group(request, context)
834
835 @twisted_async
836 def DeleteChannelgroup(self, request, context):
837 return self.core.xpon_handler.delete_channel_group(request, context)
838
839 @twisted_async
840 def GetAllChannelpartitionConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400841 return self.core.xpon_handler.get_all_channel_partition_config(
842 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400843
844 @twisted_async
845 def CreateChannelpartition(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400846 return self.core.xpon_handler.create_channel_partition(
847 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400848
849 @twisted_async
850 def UpdateChannelpartition(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400851 return self.core.xpon_handler.update_channel_partition(
852 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400853
854 @twisted_async
855 def DeleteChannelpartition(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400856 return self.core.xpon_handler.delete_channel_partition(
857 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400858
859 @twisted_async
860 def GetAllChannelpairConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400861 return self.core.xpon_handler.get_all_channel_pair_config(
862 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400863
864 @twisted_async
865 def CreateChannelpair(self, request, context):
866 return self.core.xpon_handler.create_channel_pair(request, context)
867
868 @twisted_async
869 def UpdateChannelpair(self, request, context):
870 return self.core.xpon_handler.update_channel_pair(request, context)
871
872 @twisted_async
873 def DeleteChannelpair(self, request, context):
874 return self.core.xpon_handler.delete_channel_pair(request, context)
875
876 @twisted_async
877 def GetAllChannelterminationConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400878 return self.core.xpon_handler.get_all_channel_termination_config(
879 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400880
881 @twisted_async
882 def CreateChanneltermination(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400883 return self.core.xpon_handler.create_channel_termination(
884 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400885
886 @twisted_async
887 def UpdateChanneltermination(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400888 return self.core.xpon_handler.update_channel_termination(
889 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400890
891 @twisted_async
892 def DeleteChanneltermination(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400893 return self.core.xpon_handler.delete_channel_termination(
894 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400895
896 @twisted_async
897 def GetAllOntaniConfig(self, request, context):
898 return self.core.xpon_handler.get_all_ont_ani_config(request, context)
899
900 @twisted_async
901 def CreateOntani(self, request, context):
902 return self.core.xpon_handler.create_ont_ani(request, context)
903
904 @twisted_async
905 def UpdateOntani(self, request, context):
906 return self.core.xpon_handler.update_ont_ani(request, context)
907
908 @twisted_async
909 def DeleteOntani(self, request, context):
910 return self.core.xpon_handler.delete_ont_ani(request, context)
911
912 @twisted_async
913 def GetAllVOntaniConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400914 return self.core.xpon_handler.get_all_v_ont_ani_config(
915 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400916
917 @twisted_async
918 def CreateVOntani(self, request, context):
919 return self.core.xpon_handler.create_v_ont_ani(request, context)
920
921 @twisted_async
922 def UpdateVOntani(self, request, context):
923 return self.core.xpon_handler.update_v_ont_ani(request, context)
924
925 @twisted_async
926 def DeleteVOntani(self, request, context):
927 return self.core.xpon_handler.delete_v_ont_ani(request, context)
928
929 @twisted_async
930 def GetAllVEnetConfig(self, request, context):
931 return self.core.xpon_handler.get_all_v_enet_config(request, context)
932
933 @twisted_async
934 def CreateVEnet(self, request, context):
935 return self.core.xpon_handler.create_v_enet(request, context)
936
937 @twisted_async
938 def UpdateVEnet(self, request, context):
939 return self.core.xpon_handler.update_v_enet(request, context)
940
941 @twisted_async
942 def DeleteVEnet(self, request, context):
943 return self.core.xpon_handler.delete_v_enet(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400944
945 @twisted_async
946 def GetAllTrafficDescriptorProfileData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400947 return self.core.xpon_handler.get_all_traffic_descriptor_profile_data(
948 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400949
950 @twisted_async
951 def CreateTrafficDescriptorProfileData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400952 return self.core.xpon_handler.create_traffic_descriptor_profile(
953 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400954
955 @twisted_async
956 def UpdateTrafficDescriptorProfileData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400957 return self.core.xpon_handler.update_traffic_descriptor_profile(
958 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400959
960 @twisted_async
961 def DeleteTrafficDescriptorProfileData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400962 return self.core.xpon_handler.delete_traffic_descriptor_profile(
963 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400964
965 @twisted_async
966 def GetAllTcontsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400967 return self.core.xpon_handler.get_all_tconts_config_data(
968 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400969
970 @twisted_async
971 def CreateTcontsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400972 return self.core.xpon_handler.create_tcont(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400973
974 @twisted_async
975 def UpdateTcontsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400976 return self.core.xpon_handler.update_tcont(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400977
978 @twisted_async
979 def DeleteTcontsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400980 return self.core.xpon_handler.delete_tcont(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400981
982 @twisted_async
983 def GetAllGemportsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400984 return self.core.xpon_handler.get_all_gemports_config_data(
985 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400986
987 @twisted_async
988 def CreateGemportsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400989 return self.core.xpon_handler.create_gem_port(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400990
991 @twisted_async
992 def UpdateGemportsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400993 return self.core.xpon_handler.update_gem_port(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400994
995 @twisted_async
996 def DeleteGemportsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400997 return self.core.xpon_handler.delete_gem_port(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400998
999 @twisted_async
1000 def GetAllMulticastGemportsConfigData(self, request, context):
1001 return AllMulticastGemportsConfigData()
1002
1003 @twisted_async
1004 def CreateMulticastGemportsConfigData(self, request, context):
1005 return Empty()
1006
1007 @twisted_async
1008 def UpdateMulticastGemportsConfigData(self, request, context):
1009 return Empty()
1010
1011 @twisted_async
1012 def DeleteMulticastGemportsConfigData(self, request, context):
1013 return Empty()
1014
1015 @twisted_async
1016 def GetAllMulticastDistributionSetData(self, request, context):
1017 return AllMulticastDistributionSetData()
1018
1019 @twisted_async
1020 def CreateMulticastDistributionSetData(self, request, context):
1021 return Empty()
1022
1023 @twisted_async
1024 def UpdateMulticastDistributionSetData(self, request, context):
1025 return Empty()
1026
1027 @twisted_async
1028 def DeleteMulticastDistributionSetData(self, request, context):
1029 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -04001030 # bbf_fiber rpcs end
1031
Zsolt Haraszti66862032016-11-28 14:28:39 -08001032 def StreamPacketsOut(self, request_iterator, context):
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001033 log.debug('start-stream-packets-out')
Zsolt Haraszti66862032016-11-28 14:28:39 -08001034
1035 @twisted_async
1036 def forward_packet_out(packet_out):
1037 agent = self.core.get_logical_device_agent(packet_out.id)
1038 agent.packet_out(packet_out.packet_out)
1039
1040 for request in request_iterator:
1041 forward_packet_out(packet_out=request)
1042
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001043 log.debug('stop-stream-packets-out')
1044
Zsolt Haraszti66862032016-11-28 14:28:39 -08001045 return Empty()
1046
1047 def ReceivePacketsIn(self, request, context):
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001048 log.debug('start-receive-packets-in')
1049 while self.ofagent_is_alive:
Zsolt Haraszti3300f742017-01-09 01:14:20 -08001050 try:
1051 packet_in = self.core.packet_in_queue.get(timeout=1)
1052 yield packet_in
1053 except QueueEmpty:
1054 if self.stopped:
1055 break
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001056 log.debug('stop-receive-packets-in')
Zsolt Haraszti66862032016-11-28 14:28:39 -08001057
1058 def send_packet_in(self, device_id, ofp_packet_in):
1059 """Must be called on the twisted thread"""
1060 packet_in = PacketIn(id=device_id, packet_in=ofp_packet_in)
1061 self.core.packet_in_queue.put(packet_in)
Zsolt Haraszti217a12e2016-12-19 16:37:55 -08001062
1063 def ReceiveChangeEvents(self, request, context):
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001064 log.debug('start-receive-change-events')
1065 while self.ofagent_is_alive:
Zsolt Haraszti3300f742017-01-09 01:14:20 -08001066 try:
1067 event = self.core.change_event_queue.get(timeout=1)
1068 yield event
1069 except QueueEmpty:
1070 if self.stopped:
1071 break
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001072 log.debug('stop-receive-change-events')
Zsolt Haraszti217a12e2016-12-19 16:37:55 -08001073
1074 def send_port_change_event(self, device_id, port_status):
1075 """Must be called on the twisted thread"""
1076 assert isinstance(port_status, ofp_port_status)
1077 event = ChangeEvent(id=device_id, port_status=port_status)
1078 self.core.change_event_queue.put(event)
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001079
1080
1081 @twisted_async
1082 def ListAlarmFilters(self, request, context):
1083 try:
1084 filters = self.root.get('/alarm_filters')
1085 return AlarmFilters(filters=filters)
1086 except KeyError:
1087 context.set_code(StatusCode.NOT_FOUND)
1088 return AlarmFilters()
1089
1090 @twisted_async
1091 def GetAlarmFilter(self, request, context):
1092 if '/' in request.id:
1093 context.set_details(
1094 'Malformed alarm filter id \'{}\''.format(request.id))
1095 context.set_code(StatusCode.INVALID_ARGUMENT)
1096 return AlarmFilter()
1097
1098 try:
1099 alarm_filter = self.root.get('/alarm_filters/{}'.format(request.id))
khenaidoo08d48d22017-06-29 19:42:49 -04001100
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001101 return alarm_filter
1102 except KeyError:
1103 context.set_details(
1104 'Alarm filter \'{}\' not found'.format(request.id))
1105 context.set_code(StatusCode.NOT_FOUND)
1106 return AlarmFilter()
1107
1108 @twisted_async
1109 def DeleteAlarmFilter(self, request, context):
1110 if '/' in request.id:
1111 context.set_details(
1112 'Malformed alarm filter id \'{}\''.format(request.id))
1113 context.set_code(StatusCode.INVALID_ARGUMENT)
1114 return Empty()
1115
1116 try:
1117 self.root.remove('/alarm_filters/{}'.format(request.id))
1118 except KeyError:
1119 context.set_code(StatusCode.NOT_FOUND)
1120
1121 return Empty()
1122
1123 @twisted_async
1124 def CreateAlarmFilter(self, request, context):
1125 log.info('grpc-request', request=request)
1126
1127 try:
1128 assert isinstance(request, AlarmFilter)
1129 alarm_filter = request
khenaidoo08d48d22017-06-29 19:42:49 -04001130 assert alarm_filter.id is not None, 'Local Alarm filter to be ' \
1131 'created must have id'
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001132 except AssertionError, e:
1133 context.set_details(e.message)
1134 context.set_code(StatusCode.INVALID_ARGUMENT)
1135 return AlarmFilter()
1136
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001137 # add device to tree
1138 self.root.add('/alarm_filters', alarm_filter)
1139
1140 return request
1141
1142 @twisted_async
1143 def UpdateAlarmFilter(self, request, context):
1144 if '/' in request.id:
1145 context.set_details(
1146 'Malformed alarm filter id \'{}\''.format(request.id))
1147 context.set_code(StatusCode.INVALID_ARGUMENT)
1148 return AlarmFilter()
1149
1150 try:
1151 assert isinstance(request, AlarmFilter)
1152 alarm_filter = self.root.get('/alarm_filters/{}'.format(request.id))
1153 self.root.update('/alarm_filters/{}'.format(request.id), request)
1154
1155 return request
1156 except KeyError:
1157 context.set_details(
1158 'Alarm filter \'{}\' not found'.format(request.id))
1159 context.set_code(StatusCode.NOT_FOUND)
1160 return AlarmFilter()
ggowdru236bd952017-06-20 20:32:55 -07001161
1162 @twisted_async
1163 def GetImages(self, request, context):
1164 log.info('grpc-request', request=request)
1165
1166 if '/' in request.id:
1167 context.set_details(
1168 'Malformed device id \'{}\''.format(request.id))
1169 context.set_code(StatusCode.INVALID_ARGUMENT)
1170 return Images()
1171
1172 try:
1173 device = self.root.get('/devices/' + request.id)
1174 return device.images
1175
1176 except KeyError:
1177 context.set_details(
1178 'Device \'{}\' not found'.format(request.id))
1179 context.set_code(StatusCode.NOT_FOUND)
1180 return Images()
sathishg5ae86222017-06-28 15:16:29 +05301181
1182 @twisted_async
1183 def SelfTest(self, request, context):
1184 log.info('grpc-request', request=request)
1185
1186 if '/' in request.id:
1187 context.set_details(
1188 'Malformed device id \'{}\''.format(request.id))
1189 context.set_code(StatusCode.INVALID_ARGUMENT)
1190 return SelfTestResponse()
1191
1192 try:
1193 path = '/devices/{}'.format(request.id)
1194 device = self.root.get(path)
1195
1196 agent = self.core.get_device_agent(device.id)
1197 resp = agent.self_test(device)
1198 return resp.result
1199
1200 except KeyError:
1201 context.set_details(
1202 'Device \'{}\' not found'.format(request.id))
1203 context.set_code(StatusCode.NOT_FOUND)
1204 return SelfTestResponse()
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001205
1206 def _ofagent_session_termination(self):
1207 log.debug('start-ofagent-session-termination')
1208
1209 # Stop ofagent heartbeat
1210 if self.ofagent_heartbeat_lc is not None:
1211 self.ofagent_heartbeat_lc.stop()
1212
1213 # Reset flags and assignments
1214 self.ofagent_is_alive = False
1215 self.subscriber = None
1216 self.ofagent_heartbeat_count = 0
1217
1218 # Some local services will stop (packet-in/change-events)
1219 # need to re-register them
1220 registry('grpc_server').register(
1221 add_VolthaLocalServiceServicer_to_server, self)
1222
1223 log.debug('stop-ofagent-session-termination')
1224
1225 def _ofagent_session_heartbeat(self):
1226 log.debug('start-ofagent-heartbeat')
1227 if self.ofagent_heartbeat_count > self.ofagent_heartbeat_max_count:
1228 self._ofagent_session_termination()
1229 else:
1230 self.ofagent_heartbeat_count += 1
1231
1232 log.debug('stop-ofagent-heartbeat')
1233
1234 @twisted_async
1235 def Subscribe(self, request, context):
1236 log.info('grpc-request', request=request)
1237
1238 # Check if an ofagent subscriber is assigned
1239 if self.subscriber is None:
1240 log.debug('ofagent-subscriber-request')
1241
1242 try:
1243 # Assign the request as the active subscriber
1244 self.subscriber = OfAgentSubscriber(
1245 ofagent_id=request.ofagent_id,
1246 voltha_id=self.instance_id
1247 )
1248
1249 # Start the hearbeat
1250 self.ofagent_heartbeat_count = 0
1251 self.ofagent_heartbeat_lc = task.LoopingCall(self._ofagent_session_heartbeat)
1252 self.ofagent_heartbeat_lc.start(self.ofagent_heartbeat_delay)
1253
1254 log.debug('ofagent-subscriber-connected', subscriber=self.subscriber)
1255
1256 except _Rendezvous, e:
1257 log.error('ofagent-subscriber-failure', exception=repr(e), status=e.code())
1258
1259 except Exception as e:
1260 log.exception('ofagent-subscriber-unexpected-failure', exception=repr(e))
1261
1262 elif self.subscriber.ofagent_id == request.ofagent_id:
1263 log.debug('ofagent-subscriber-matches-assigned',
1264 current=self.subscriber)
1265 # reset counter
1266 self.ofagent_heartbeat_count = 0
1267
1268 else:
1269 log.debug('ofagent-subscriber-not-matching-assigned',
1270 current=self.subscriber)
1271
1272 return self.subscriber