blob: a172e51d0cc7aada079ca510b8079d2254d5bc63 [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
21
22from common.utils.grpc_utils import twisted_async
khenaidooa8588f22017-06-16 12:13:34 -040023from common.utils.id_generation import create_cluster_device_id
Zsolt Haraszti66862032016-11-28 14:28:39 -080024from voltha.core.config.config_root import ConfigRoot
Zsolt Haraszti217a12e2016-12-19 16:37:55 -080025from voltha.protos.openflow_13_pb2 import PacketIn, Flows, FlowGroups, \
26 ofp_port_status
Zsolt Haraszti66862032016-11-28 14:28:39 -080027from voltha.protos.voltha_pb2 import \
28 add_VolthaLocalServiceServicer_to_server, VolthaLocalServiceServicer, \
29 VolthaInstance, Adapters, LogicalDevices, LogicalDevice, Ports, \
30 LogicalPorts, Devices, Device, DeviceType, \
Stephane Barbarie4db8ca22017-04-24 10:30:20 -040031 DeviceTypes, DeviceGroups, DeviceGroup, AdminState, OperStatus, ChangeEvent, \
sathishg5ae86222017-06-28 15:16:29 +053032 AlarmFilter, AlarmFilters, SelfTestResponse
Lydia Fang01f2e852017-06-28 17:24:58 -070033from voltha.protos.device_pb2 import PmConfigs, Images, ImageDownload, ImageDownloads
34from voltha.protos.common_pb2 import OperationResp
Zsolt Haraszti66862032016-11-28 14:28:39 -080035from voltha.registry import registry
Nikolay Titov89004ec2017-06-19 18:22:42 -040036from requests.api import request
Zsolt Haraszti66862032016-11-28 14:28:39 -080037
38log = structlog.get_logger()
39
40
41class LocalHandler(VolthaLocalServiceServicer):
khenaidoo032d3302017-06-09 14:50:04 -040042 def __init__(self, core, instance_id, core_store_id, **init_kw):
Zsolt Haraszti66862032016-11-28 14:28:39 -080043 self.core = core
khenaidoo032d3302017-06-09 14:50:04 -040044 self.instance_id = instance_id
45 self.core_store_id = core_store_id
Zsolt Haraszti66862032016-11-28 14:28:39 -080046 self.init_kw = init_kw
47 self.root = None
khenaidoo032d3302017-06-09 14:50:04 -040048 self.started_with_existing_data = False
Zsolt Haraszti66862032016-11-28 14:28:39 -080049 self.stopped = False
50
Ryan Van Gilder5a0ab622017-03-01 16:39:25 -080051 def start(self, config_backend=None):
Zsolt Haraszti66862032016-11-28 14:28:39 -080052 log.debug('starting')
Ryan Van Gilder5a0ab622017-03-01 16:39:25 -080053 if config_backend:
54 if 'root' in config_backend:
khenaidoo032d3302017-06-09 14:50:04 -040055 # This is going to block the entire reactor until loading is
56 # completed
57 log.info('loading-config-from-persisted-backend')
58 try:
59 self.root = ConfigRoot.load(VolthaInstance,
60 kv_store=config_backend)
61 self.started_with_existing_data = True
62 except Exception, e:
63 log.exception('Failure-loading-from-backend', e=e)
Ryan Van Gilder5a0ab622017-03-01 16:39:25 -080064 else:
khenaidoo032d3302017-06-09 14:50:04 -040065 log.info('initializing-a-new-config')
Khen Nursimulud068d812017-03-06 11:44:18 -050066 self.root = ConfigRoot(VolthaInstance(**self.init_kw),
67 kv_store=config_backend)
Ryan Van Gilder5a0ab622017-03-01 16:39:25 -080068 else:
69 self.root = ConfigRoot(VolthaInstance(**self.init_kw))
70
Nikolay Titov89004ec2017-06-19 18:22:42 -040071 self.core.xpon_handler.start(self.root)
72
Zsolt Haraszti66862032016-11-28 14:28:39 -080073 registry('grpc_server').register(
74 add_VolthaLocalServiceServicer_to_server, self)
75 log.info('started')
76 return self
77
78 def stop(self):
79 log.debug('stopping')
80 self.stopped = True
81 log.info('stopped')
82
83 def get_proxy(self, path, exclusive=False):
84 return self.root.get_proxy(path, exclusive)
85
khenaidoo032d3302017-06-09 14:50:04 -040086 def has_started_with_existing_data(self):
87 return self.started_with_existing_data
88
Zsolt Haraszti66862032016-11-28 14:28:39 -080089 # gRPC service method implementations. BE CAREFUL; THESE ARE CALLED ON
90 # the gRPC threadpool threads.
91
92 @twisted_async
93 def GetVolthaInstance(self, request, context):
94 log.info('grpc-request', request=request)
95 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
96 res = self.root.get('/', depth=depth)
97 return res
98
99 @twisted_async
100 def GetHealth(self, request, context):
101 log.info('grpc-request', request=request)
102 return self.root.get('/health')
103
104 @twisted_async
105 def ListAdapters(self, request, context):
106 log.info('grpc-request', request=request)
107 items = self.root.get('/adapters')
108 return Adapters(items=items)
109
110 @twisted_async
111 def ListLogicalDevices(self, request, context):
112 log.info('grpc-request', request=request)
113 items = self.root.get('/logical_devices')
114 return LogicalDevices(items=items)
115
116 @twisted_async
117 def GetLogicalDevice(self, request, context):
118 log.info('grpc-request', request=request)
119
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800120 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
121
Zsolt Haraszti66862032016-11-28 14:28:39 -0800122 if '/' in request.id:
123 context.set_details(
124 'Malformed logical device id \'{}\''.format(request.id))
125 context.set_code(StatusCode.INVALID_ARGUMENT)
126 return LogicalDevice()
127
128 try:
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800129 return self.root.get('/logical_devices/' + request.id, depth=depth)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800130 except KeyError:
131 context.set_details(
132 'Logical device \'{}\' not found'.format(request.id))
133 context.set_code(StatusCode.NOT_FOUND)
134 return LogicalDevice()
135
136 @twisted_async
137 def ListLogicalDevicePorts(self, request, context):
138 log.info('grpc-request', request=request)
139
140 if '/' in request.id:
141 context.set_details(
142 'Malformed logical device id \'{}\''.format(request.id))
143 context.set_code(StatusCode.INVALID_ARGUMENT)
144 return LogicalPorts()
145
146 try:
Khen Nursimulud068d812017-03-06 11:44:18 -0500147 items = self.root.get(
148 '/logical_devices/{}/ports'.format(request.id))
Zsolt Haraszti66862032016-11-28 14:28:39 -0800149 return LogicalPorts(items=items)
150 except KeyError:
151 context.set_details(
152 'Logical device \'{}\' not found'.format(request.id))
153 context.set_code(StatusCode.NOT_FOUND)
154 return LogicalPorts()
155
156 @twisted_async
157 def ListLogicalDeviceFlows(self, request, context):
158 log.info('grpc-request', request=request)
159
160 if '/' in request.id:
161 context.set_details(
162 'Malformed logical device id \'{}\''.format(request.id))
163 context.set_code(StatusCode.INVALID_ARGUMENT)
164 return Flows()
165
166 try:
Khen Nursimulud068d812017-03-06 11:44:18 -0500167 flows = self.root.get(
168 '/logical_devices/{}/flows'.format(request.id))
Zsolt Haraszti66862032016-11-28 14:28:39 -0800169 return flows
170 except KeyError:
171 context.set_details(
172 'Logical device \'{}\' not found'.format(request.id))
173 context.set_code(StatusCode.NOT_FOUND)
174 return Flows()
175
Zsolt Haraszti66862032016-11-28 14:28:39 -0800176 @twisted_async
177 def UpdateLogicalDeviceFlowTable(self, request, context):
178 log.info('grpc-request', request=request)
179
180 if '/' in request.id:
181 context.set_details(
182 'Malformed logical device id \'{}\''.format(request.id))
183 context.set_code(StatusCode.INVALID_ARGUMENT)
184 return Empty()
185
186 try:
187 agent = self.core.get_logical_device_agent(request.id)
188 agent.update_flow_table(request.flow_mod)
189 return Empty()
190 except KeyError:
191 context.set_details(
192 'Logical device \'{}\' not found'.format(request.id))
193 context.set_code(StatusCode.NOT_FOUND)
194 return Empty()
195
196 @twisted_async
197 def ListLogicalDeviceFlowGroups(self, request, context):
198 log.info('grpc-request', request=request)
199
200 if '/' in request.id:
201 context.set_details(
202 'Malformed logical device id \'{}\''.format(request.id))
203 context.set_code(StatusCode.INVALID_ARGUMENT)
204 return FlowGroups()
205
206 try:
207 groups = self.root.get(
208 '/logical_devices/{}/flow_groups'.format(request.id))
209 return groups
210 except KeyError:
211 context.set_details(
212 'Logical device \'{}\' not found'.format(request.id))
213 context.set_code(StatusCode.NOT_FOUND)
214 return FlowGroups()
215
216 @twisted_async
217 def UpdateLogicalDeviceFlowGroupTable(self, request, context):
218 log.info('grpc-request', request=request)
219
220 if '/' in request.id:
221 context.set_details(
222 'Malformed logical device id \'{}\''.format(request.id))
223 context.set_code(StatusCode.INVALID_ARGUMENT)
224 return Empty()
225
226 try:
227 agent = self.core.get_logical_device_agent(request.id)
228 agent.update_group_table(request.group_mod)
229 return Empty()
230 except KeyError:
231 context.set_details(
232 'Logical device \'{}\' not found'.format(request.id))
233 context.set_code(StatusCode.NOT_FOUND)
234 return Empty()
235
236 @twisted_async
237 def ListDevices(self, request, context):
238 log.info('grpc-request', request=request)
239 items = self.root.get('/devices')
240 return Devices(items=items)
241
242 @twisted_async
243 def GetDevice(self, request, context):
244 log.info('grpc-request', request=request)
245
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800246 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
247
Zsolt Haraszti66862032016-11-28 14:28:39 -0800248 if '/' in request.id:
249 context.set_details(
250 'Malformed device id \'{}\''.format(request.id))
251 context.set_code(StatusCode.INVALID_ARGUMENT)
252 return Device()
253
254 try:
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800255 return self.root.get('/devices/' + request.id, depth=depth)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800256 except KeyError:
257 context.set_details(
258 'Device \'{}\' not found'.format(request.id))
259 context.set_code(StatusCode.NOT_FOUND)
260 return Device()
261
262 @twisted_async
263 def CreateDevice(self, request, context):
264 log.info('grpc-request', request=request)
265
266 known_device_types = dict(
267 (dt.id, dt) for dt in self.root.get('/device_types'))
268
269 try:
270 assert isinstance(request, Device)
271 device = request
272 assert device.id == '', 'Device to be created cannot have id yet'
273 assert device.type in known_device_types, \
274 'Unknown device type \'{}\''.format(device.type)
275 assert device.admin_state in (AdminState.UNKNOWN,
276 AdminState.PREPROVISIONED), \
277 'Newly created device cannot be ' \
278 'in admin state \'{}\''.format(device.admin_state)
279
280 except AssertionError, e:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400281 context.set_details(e.message)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800282 context.set_code(StatusCode.INVALID_ARGUMENT)
283 return Device()
284
285 # fill additional data
khenaidooa8588f22017-06-16 12:13:34 -0400286 device.id = create_cluster_device_id(self.core_store_id)
287 log.debug('device-id-created', device_id=device.id)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800288 device_type = known_device_types[device.type]
289 device.adapter = device_type.adapter
290 if device.admin_state != AdminState.PREPROVISIONED:
291 device.admin_state = AdminState.PREPROVISIONED
292 device.oper_status = OperStatus.UNKNOWN
293
294 # add device to tree
295 self.root.add('/devices', device)
296
297 return request
298
299 @twisted_async
Khen Nursimulud068d812017-03-06 11:44:18 -0500300 def EnableDevice(self, request, context):
Zsolt Haraszti66862032016-11-28 14:28:39 -0800301 log.info('grpc-request', request=request)
302
303 if '/' in request.id:
304 context.set_details(
305 'Malformed device id \'{}\''.format(request.id))
306 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400307 return Empty()
Zsolt Haraszti66862032016-11-28 14:28:39 -0800308
309 try:
310 path = '/devices/{}'.format(request.id)
311 device = self.root.get(path)
Khen Nursimulud068d812017-03-06 11:44:18 -0500312 assert device.admin_state in (AdminState.PREPROVISIONED,
313 AdminState.DISABLED), \
314 'Device to enable cannot be ' \
315 'in admin state \'{}\''.format(device.admin_state)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800316 device.admin_state = AdminState.ENABLED
317 self.root.update(path, device, strict=True)
318
Khen Nursimulud068d812017-03-06 11:44:18 -0500319 except AssertionError, e:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400320 context.set_details(e.message)
Khen Nursimulud068d812017-03-06 11:44:18 -0500321 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimulud068d812017-03-06 11:44:18 -0500322
323 except KeyError:
324 context.set_details(
325 'Device \'{}\' not found'.format(request.id))
326 context.set_code(StatusCode.NOT_FOUND)
327
328 return Empty()
329
330 @twisted_async
331 def DisableDevice(self, request, context):
332 log.info('grpc-request', request=request)
333
334 if '/' in request.id:
335 context.set_details(
336 'Malformed device id \'{}\''.format(request.id))
337 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400338 return Empty()
Khen Nursimulud068d812017-03-06 11:44:18 -0500339 try:
340 path = '/devices/{}'.format(request.id)
341 device = self.root.get(path)
342 assert device.admin_state == AdminState.ENABLED, \
343 'Device to disable cannot be ' \
344 'in admin state \'{}\''.format(device.admin_state)
345 device.admin_state = AdminState.DISABLED
346 self.root.update(path, device, strict=True)
347
348 except AssertionError, e:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400349 context.set_details(e.message)
Khen Nursimulud068d812017-03-06 11:44:18 -0500350 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimulud068d812017-03-06 11:44:18 -0500351
352 except KeyError:
353 context.set_details(
354 'Device \'{}\' not found'.format(request.id))
355 context.set_code(StatusCode.NOT_FOUND)
356
khenaidoo032d3302017-06-09 14:50:04 -0400357 except Exception, e:
358 log.exception('disable-exception', e=e)
359
Khen Nursimulud068d812017-03-06 11:44:18 -0500360 return Empty()
361
362 @twisted_async
363 def RebootDevice(self, request, context):
364 log.info('grpc-request', request=request)
365
366 if '/' in request.id:
367 context.set_details(
368 'Malformed device id \'{}\''.format(request.id))
369 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400370 return Empty()
Khen Nursimulud068d812017-03-06 11:44:18 -0500371
372 try:
373 path = '/devices/{}'.format(request.id)
374 device = self.root.get(path)
Lydia Fang01f2e852017-06-28 17:24:58 -0700375 assert device.admin_state != AdminState.DOWNLOADING_IMAGE, \
376 'Device to reboot cannot be ' \
377 'in admin state \'{}\''.format(device.admin_state)
Khen Nursimulud068d812017-03-06 11:44:18 -0500378 agent = self.core.get_device_agent(device.id)
379 agent.reboot_device(device)
380
Khen Nursimulud068d812017-03-06 11:44:18 -0500381 except KeyError:
382 context.set_details(
383 'Device \'{}\' not found'.format(request.id))
384 context.set_code(StatusCode.NOT_FOUND)
385
386 return Empty()
387
388 @twisted_async
Lydia Fang01f2e852017-06-28 17:24:58 -0700389 def DownloadImage(self, request, context):
390 log.info('grpc-request', request=request)
391
392 if '/' in request.id:
393 context.set_details(
394 'Malformed device id \'{}\''.format(request.id))
395 context.set_code(StatusCode.INVALID_ARGUMENT)
396 return OperationResp(code=OperationResp.OPERATION_FAILURE)
397
398 try:
399 path = '/devices/{}'.format(request.id)
400 device = self.root.get(path)
401 assert isinstance(request, ImageDownload)
402 self.root.add('/devices/{}/image_downloads'.\
403 format(request.id), request)
404 assert device.admin_state == AdminState.ENABLED, \
405 'Device to DOWNLOADING_IMAGE cannot be ' \
406 'in admin state \'{}\''.format(device.admin_state)
407 device.admin_state = AdminState.DOWNLOADING_IMAGE
408 self.root.update(path, device, strict=True)
409 agent = self.core.get_device_agent(device.id)
410 agent.register_image_download(request)
411 return OperationResp(code=OperationResp.OPERATION_SUCCESS)
412
413 except AssertionError as e:
414 context.set_details(e.message)
415 context.set_code(StatusCode.INVALID_ARGUMENT)
416 return OperationResp(code=OperationResp.OPERATION_UNSUPPORTED)
417
418 except KeyError:
419 context.set_details(
420 'Device \'{}\' not found'.format(request.id))
421 context.set_code(StatusCode.NOT_FOUND)
422 return OperationResp(code=OperationResp.OPERATION_FAILURE)
423
424 except Exception as e:
425 log.exception(e.message)
426 context.set_code(StatusCode.NOT_FOUND)
427 return OperationResp(code=OperationResp.OPERATION_FAILURE)
428
429 @twisted_async
430 def GetImageDownloadStatus(self, request, context):
431 log.info('grpc-request', request=request)
432
433 if '/' in request.id:
434 context.set_details(
435 'Malformed device id \'{}\''.format(request.id))
436 context.set_code(StatusCode.INVALID_ARGUMENT)
437 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
438 return response
439
440 try:
441 path = '/devices/{}'.format(request.id)
442 device = self.root.get(path)
443 agent = self.core.get_device_agent(device.id)
444 img_dnld = self.root.get('/devices/{}/image_downloads/{}'.\
445 format(request.id, request.name))
446 agent.get_image_download_status(img_dnld)
447 try:
448 response = self.root.get('/devices/{}/image_downloads/{}'.\
449 format(request.id, request.name))
450 except Exception as e:
451 log.exception(e.message)
452 return response
453
454 except KeyError:
455 context.set_details(
456 'Device \'{}\' not found'.format(request.id))
457 context.set_code(StatusCode.NOT_FOUND)
458 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
459 return response
460 except Exception as e:
461 log.exception(e.message)
462 response = ImageDownload(state=ImageDownload.DOWNLOAD_FAILED)
463 return response
464
465 @twisted_async
466 def GetImageDownload(self, request, context):
467 log.info('grpc-request', request=request)
468
469 if '/' in request.id:
470 context.set_details(
471 'Malformed device id \'{}\''.format(request.id))
472 context.set_code(StatusCode.INVALID_ARGUMENT)
473 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
474 return response
475
476 try:
477 response = self.root.get('/devices/{}/image_downloads/{}'.\
478 format(request.id, request.name))
479 return response
480
481 except KeyError:
482 context.set_details(
483 'Device \'{}\' not found'.format(request.id))
484 context.set_code(StatusCode.NOT_FOUND)
485 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
486 return response
487
488 @twisted_async
489 def ListImageDownloads(self, request, context):
490 log.info('grpc-request', request=request)
491
492 if '/' in request.id:
493 context.set_details(
494 'Malformed device id \'{}\''.format(request.id))
495 context.set_code(StatusCode.INVALID_ARGUMENT)
496 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
497 return response
498
499 try:
500 response = self.root.get('/devices/{}/image_downloads'.\
501 format(request.id))
502 return ImageDownloads(items=response)
503
504 except KeyError:
505 context.set_details(
506 'Device \'{}\' not found'.format(request.id))
507 context.set_code(StatusCode.NOT_FOUND)
508 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
509 return response
510
511 @twisted_async
512 def CancelImageDownload(self, request, context):
513 log.info('grpc-request', request=request)
514
515 if '/' in request.id:
516 context.set_details(
517 'Malformed device id \'{}\''.format(request.id))
518 context.set_code(StatusCode.INVALID_ARGUMENT)
519 return OperationResp(code=OperationResp.OPERATION_FAILURE)
520
521 try:
522 assert isinstance(request, ImageDownload)
523 path = '/devices/{}'.format(request.id)
524 device = self.root.get(path)
525 assert device.admin_state == AdminState.DOWNLOADING_IMAGE, \
526 'Device to cancel DOWNLOADING_IMAGE cannot be ' \
527 'in admin state \'{}\''.format(device.admin_state)
528 agent = self.core.get_device_agent(device.id)
529 agent.cancel_image_download(request)
530 return OperationResp(code=OperationResp.OPERATION_SUCCESS)
531
532 except KeyError:
533 context.set_details(
534 'Device \'{}\' not found'.format(request.id))
535 context.set_code(StatusCode.NOT_FOUND)
536 return OperationResp(code=OperationResp.OPERATION_FAILURE)
537
538 @twisted_async
539 def ActivateImageUpdate(self, request, context):
540 log.info('grpc-request', request=request)
541
542 if '/' in request.id:
543 context.set_details(
544 'Malformed device id \'{}\''.format(request.id))
545 context.set_code(StatusCode.INVALID_ARGUMENT)
546 return OperationResp(code=OperationResp.OPERATION_FAILURE)
547
548 try:
549 assert isinstance(request, ImageDownload)
550 path = '/devices/{}'.format(request.id)
551 device = self.root.get(path)
552 assert device.admin_state == AdminState.ENABLED, \
553 'Device to activate image cannot be ' \
554 'in admin state \'{}\''.format(device.admin_state)
555 agent = self.core.get_device_agent(device.id)
556 agent.activate_image_update(request)
557 return OperationResp(code=OperationResp.OPERATION_SUCCESS)
558
559 except KeyError:
560 context.set_details(
561 'Device \'{}\' not found'.format(request.id))
562 context.set_code(StatusCode.NOT_FOUND)
563 return OperationResp(code=OperationResp.OPERATION_FAILURE)
564
565 @twisted_async
566 def RevertImageUpdate(self, request, context):
567 log.info('grpc-request', request=request)
568
569 if '/' in request.id:
570 context.set_details(
571 'Malformed device id \'{}\''.format(request.id))
572 context.set_code(StatusCode.INVALID_ARGUMENT)
573 return OperationResp(code=OperationResp.OPERATION_FAILURE)
574
575 try:
576 assert isinstance(request, ImageDownload)
577 path = '/devices/{}'.format(request.id)
578 device = self.root.get(path)
579 assert device.admin_state == AdminState.ENABLED, \
580 'Device to revert image cannot be ' \
581 'in admin state \'{}\''.format(device.admin_state)
582 agent = self.core.get_device_agent(device.id)
583 agent.revert_image_update(request)
584 return OperationResp(code=OperationResp.OPERATION_SUCCESS)
585
586 except KeyError:
587 context.set_details(
588 'Device \'{}\' not found'.format(request.id))
589 context.set_code(StatusCode.NOT_FOUND)
590 return OperationResp(code=OperationResp.OPERATION_FAILURE)
591
592 @twisted_async
Khen Nursimulud068d812017-03-06 11:44:18 -0500593 def DeleteDevice(self, request, context):
594 log.info('grpc-request', request=request)
595
596 if '/' in request.id:
597 context.set_details(
598 'Malformed device id \'{}\''.format(request.id))
599 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400600 return Empty()
Khen Nursimulud068d812017-03-06 11:44:18 -0500601
602 try:
603 path = '/devices/{}'.format(request.id)
604 device = self.root.get(path)
605 assert device.admin_state == AdminState.DISABLED, \
606 'Device to delete cannot be ' \
607 'in admin state \'{}\''.format(device.admin_state)
608
609 self.root.remove(path)
610
611 except AssertionError, e:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400612 context.set_details(e.message)
Khen Nursimulud068d812017-03-06 11:44:18 -0500613 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimulud068d812017-03-06 11:44:18 -0500614
Zsolt Haraszti66862032016-11-28 14:28:39 -0800615 except KeyError:
616 context.set_details(
617 'Device \'{}\' not found'.format(request.id))
618 context.set_code(StatusCode.NOT_FOUND)
619
620 return Empty()
621
622 @twisted_async
623 def ListDevicePorts(self, request, context):
624 log.info('grpc-request', request=request)
625
626 if '/' in request.id:
627 context.set_details(
628 'Malformed device id \'{}\''.format(request.id))
629 context.set_code(StatusCode.INVALID_ARGUMENT)
630 return Ports()
631
632 try:
633 items = self.root.get('/devices/{}/ports'.format(request.id))
634 return Ports(items=items)
635 except KeyError:
636 context.set_details(
637 'Device \'{}\' not found'.format(request.id))
638 context.set_code(StatusCode.NOT_FOUND)
639 return Ports()
640
Sergio Slobodriana2eb52b2017-03-07 12:24:46 -0500641 @twisted_async
642 def ListDevicePmConfigs(self, request, context):
Sergio Slobodrian71960022017-03-09 10:20:57 -0500643 log.info('grpc-request', request=request)
Sergio Slobodriana2eb52b2017-03-07 12:24:46 -0500644
Sergio Slobodrian71960022017-03-09 10:20:57 -0500645 if '/' in request.id:
646 context.set_details(
647 'Malformed device id \'{}\''.format(request.id))
648 context.set_code(StatusCode.INVALID_ARGUMENT)
649 return PmConfigs()
650
651 try:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400652 pm_configs = self.root.get(
653 '/devices/{}/pm_configs'.format(request.id))
Sergio Slobodrian2db4c102017-03-09 22:29:23 -0500654 pm_configs.id = request.id
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400655 log.info('device-for-pms', pm_configs=pm_configs)
Sergio Slobodrian2db4c102017-03-09 22:29:23 -0500656 return pm_configs
Sergio Slobodrian71960022017-03-09 10:20:57 -0500657 except KeyError:
658 context.set_details(
659 'Device \'{}\' not found'.format(request.id))
660 context.set_code(StatusCode.NOT_FOUND)
661 return PmConfigs()
662
Sergio Slobodriana2eb52b2017-03-07 12:24:46 -0500663 @twisted_async
664 def UpdateDevicePmConfigs(self, request, context):
Sergio Slobodrian2db4c102017-03-09 22:29:23 -0500665 log.info('grpc-request', request=request)
666
667 if '/' in request.id:
668 context.set_details(
669 'Malformed logical device id \'{}\''.format(request.id))
670 context.set_code(StatusCode.INVALID_ARGUMENT)
671 return Empty()
672
673 try:
674 device = self.root.get('/devices/{}'.format(request.id))
675 agent = self.core.get_device_agent(request.id)
676 agent.update_device_pm_config(request)
677 return Empty()
678 except KeyError:
679 context.set_details(
680 'Device \'{}\' not found'.format(request.id))
681 context.set_code(StatusCode.NOT_FOUND)
682 return Empty()
Sergio Slobodriana2eb52b2017-03-07 12:24:46 -0500683
Zsolt Haraszti66862032016-11-28 14:28:39 -0800684 @twisted_async
685 def ListDeviceFlows(self, request, context):
686 log.info('grpc-request', request=request)
687
688 if '/' in request.id:
689 context.set_details(
690 'Malformed device id \'{}\''.format(request.id))
691 context.set_code(StatusCode.INVALID_ARGUMENT)
692 return Flows()
693
694 try:
695 flows = self.root.get('/devices/{}/flows'.format(request.id))
696 return flows
697 except KeyError:
698 context.set_details(
699 'Device \'{}\' not found'.format(request.id))
700 context.set_code(StatusCode.NOT_FOUND)
701 return Flows()
702
Zsolt Haraszti66862032016-11-28 14:28:39 -0800703 @twisted_async
704 def ListDeviceFlowGroups(self, request, context):
705 log.info('grpc-request', request=request)
706
707 if '/' in request.id:
708 context.set_details(
709 'Malformed device id \'{}\''.format(request.id))
710 context.set_code(StatusCode.INVALID_ARGUMENT)
711 return FlowGroups()
712
713 try:
Khen Nursimulud068d812017-03-06 11:44:18 -0500714 groups = self.root.get(
715 '/devices/{}/flow_groups'.format(request.id))
Zsolt Haraszti66862032016-11-28 14:28:39 -0800716 return groups
717 except KeyError:
718 context.set_details(
719 'Device \'{}\' not found'.format(request.id))
720 context.set_code(StatusCode.NOT_FOUND)
721 return FlowGroups()
722
723 @twisted_async
724 def ListDeviceTypes(self, request, context):
725 log.info('grpc-request', request=request)
726 items = self.root.get('/device_types')
727 return DeviceTypes(items=items)
728
729 @twisted_async
730 def GetDeviceType(self, request, context):
731 log.info('grpc-request', request=request)
732
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800733 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
734
Zsolt Haraszti66862032016-11-28 14:28:39 -0800735 if '/' in request.id:
736 context.set_details(
737 'Malformed device type id \'{}\''.format(request.id))
738 context.set_code(StatusCode.INVALID_ARGUMENT)
739 return DeviceType()
740
741 try:
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800742 return self.root.get('/device_types/' + request.id, depth=depth)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800743 except KeyError:
744 context.set_details(
745 'Device type \'{}\' not found'.format(request.id))
746 context.set_code(StatusCode.NOT_FOUND)
747 return DeviceType()
748
749 @twisted_async
750 def ListDeviceGroups(self, request, context):
751 log.info('grpc-request', request=request)
752 # TODO is this mapped to tree or taken from coordinator?
753 items = self.root.get('/device_groups')
754 return DeviceGroups(items=items)
755
756 @twisted_async
757 def GetDeviceGroup(self, request, context):
758 log.info('grpc-request', request=request)
759
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800760 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
761
Zsolt Haraszti66862032016-11-28 14:28:39 -0800762 if '/' in request.id:
763 context.set_details(
764 'Malformed device group id \'{}\''.format(request.id))
765 context.set_code(StatusCode.INVALID_ARGUMENT)
766 return DeviceGroup()
767
768 # TODO is this mapped to tree or taken from coordinator?
769 try:
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800770 return self.root.get('/device_groups/' + request.id, depth=depth)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800771 except KeyError:
772 context.set_details(
773 'Device group \'{}\' not found'.format(request.id))
774 context.set_code(StatusCode.NOT_FOUND)
775 return DeviceGroup()
776
Nikolay Titov89004ec2017-06-19 18:22:42 -0400777 # bbf_fiber rpcs start
778 @twisted_async
779 def GetAllChannelgroupConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400780 return self.core.xpon_handler.get_all_channel_group_config(
781 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400782
783 @twisted_async
784 def CreateChannelgroup(self, request, context):
785 return self.core.xpon_handler.create_channel_group(request, context)
786
787 @twisted_async
788 def UpdateChannelgroup(self, request, context):
789 return self.core.xpon_handler.update_channel_group(request, context)
790
791 @twisted_async
792 def DeleteChannelgroup(self, request, context):
793 return self.core.xpon_handler.delete_channel_group(request, context)
794
795 @twisted_async
796 def GetAllChannelpartitionConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400797 return self.core.xpon_handler.get_all_channel_partition_config(
798 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400799
800 @twisted_async
801 def CreateChannelpartition(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400802 return self.core.xpon_handler.create_channel_partition(
803 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400804
805 @twisted_async
806 def UpdateChannelpartition(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400807 return self.core.xpon_handler.update_channel_partition(
808 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400809
810 @twisted_async
811 def DeleteChannelpartition(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400812 return self.core.xpon_handler.delete_channel_partition(
813 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400814
815 @twisted_async
816 def GetAllChannelpairConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400817 return self.core.xpon_handler.get_all_channel_pair_config(
818 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400819
820 @twisted_async
821 def CreateChannelpair(self, request, context):
822 return self.core.xpon_handler.create_channel_pair(request, context)
823
824 @twisted_async
825 def UpdateChannelpair(self, request, context):
826 return self.core.xpon_handler.update_channel_pair(request, context)
827
828 @twisted_async
829 def DeleteChannelpair(self, request, context):
830 return self.core.xpon_handler.delete_channel_pair(request, context)
831
832 @twisted_async
833 def GetAllChannelterminationConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400834 return self.core.xpon_handler.get_all_channel_termination_config(
835 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400836
837 @twisted_async
838 def CreateChanneltermination(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400839 return self.core.xpon_handler.create_channel_termination(
840 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400841
842 @twisted_async
843 def UpdateChanneltermination(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400844 return self.core.xpon_handler.update_channel_termination(
845 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400846
847 @twisted_async
848 def DeleteChanneltermination(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400849 return self.core.xpon_handler.delete_channel_termination(
850 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400851
852 @twisted_async
853 def GetAllOntaniConfig(self, request, context):
854 return self.core.xpon_handler.get_all_ont_ani_config(request, context)
855
856 @twisted_async
857 def CreateOntani(self, request, context):
858 return self.core.xpon_handler.create_ont_ani(request, context)
859
860 @twisted_async
861 def UpdateOntani(self, request, context):
862 return self.core.xpon_handler.update_ont_ani(request, context)
863
864 @twisted_async
865 def DeleteOntani(self, request, context):
866 return self.core.xpon_handler.delete_ont_ani(request, context)
867
868 @twisted_async
869 def GetAllVOntaniConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400870 return self.core.xpon_handler.get_all_v_ont_ani_config(
871 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400872
873 @twisted_async
874 def CreateVOntani(self, request, context):
875 return self.core.xpon_handler.create_v_ont_ani(request, context)
876
877 @twisted_async
878 def UpdateVOntani(self, request, context):
879 return self.core.xpon_handler.update_v_ont_ani(request, context)
880
881 @twisted_async
882 def DeleteVOntani(self, request, context):
883 return self.core.xpon_handler.delete_v_ont_ani(request, context)
884
885 @twisted_async
886 def GetAllVEnetConfig(self, request, context):
887 return self.core.xpon_handler.get_all_v_enet_config(request, context)
888
889 @twisted_async
890 def CreateVEnet(self, request, context):
891 return self.core.xpon_handler.create_v_enet(request, context)
892
893 @twisted_async
894 def UpdateVEnet(self, request, context):
895 return self.core.xpon_handler.update_v_enet(request, context)
896
897 @twisted_async
898 def DeleteVEnet(self, request, context):
899 return self.core.xpon_handler.delete_v_enet(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -0400900
901 @twisted_async
902 def GetAllTrafficDescriptorProfileData(self, request, context):
903 return AllTrafficDescriptorProfileData()
904
905 @twisted_async
906 def CreateTrafficDescriptorProfileData(self, request, context):
907 return Empty()
908
909 @twisted_async
910 def UpdateTrafficDescriptorProfileData(self, request, context):
911 return Empty()
912
913 @twisted_async
914 def DeleteTrafficDescriptorProfileData(self, request, context):
915 return Empty()
916
917 @twisted_async
918 def GetAllTcontsConfigData(self, request, context):
919 return AllTcontsConfigData()
920
921 @twisted_async
922 def CreateTcontsConfigData(self, request, context):
923 return Empty()
924
925 @twisted_async
926 def UpdateTcontsConfigData(self, request, context):
927 return Empty()
928
929 @twisted_async
930 def DeleteTcontsConfigData(self, request, context):
931 return Empty()
932
933 @twisted_async
934 def GetAllGemportsConfigData(self, request, context):
935 return AllGemportsConfigData()
936
937 @twisted_async
938 def CreateGemportsConfigData(self, request, context):
939 return Empty()
940
941 @twisted_async
942 def UpdateGemportsConfigData(self, request, context):
943 return Empty()
944
945 @twisted_async
946 def DeleteGemportsConfigData(self, request, context):
947 return Empty()
948
949 @twisted_async
950 def GetAllMulticastGemportsConfigData(self, request, context):
951 return AllMulticastGemportsConfigData()
952
953 @twisted_async
954 def CreateMulticastGemportsConfigData(self, request, context):
955 return Empty()
956
957 @twisted_async
958 def UpdateMulticastGemportsConfigData(self, request, context):
959 return Empty()
960
961 @twisted_async
962 def DeleteMulticastGemportsConfigData(self, request, context):
963 return Empty()
964
965 @twisted_async
966 def GetAllMulticastDistributionSetData(self, request, context):
967 return AllMulticastDistributionSetData()
968
969 @twisted_async
970 def CreateMulticastDistributionSetData(self, request, context):
971 return Empty()
972
973 @twisted_async
974 def UpdateMulticastDistributionSetData(self, request, context):
975 return Empty()
976
977 @twisted_async
978 def DeleteMulticastDistributionSetData(self, request, context):
979 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -0400980 # bbf_fiber rpcs end
981
Zsolt Haraszti66862032016-11-28 14:28:39 -0800982 def StreamPacketsOut(self, request_iterator, context):
983
984 @twisted_async
985 def forward_packet_out(packet_out):
986 agent = self.core.get_logical_device_agent(packet_out.id)
987 agent.packet_out(packet_out.packet_out)
988
989 for request in request_iterator:
990 forward_packet_out(packet_out=request)
991
992 return Empty()
993
994 def ReceivePacketsIn(self, request, context):
995 while 1:
Zsolt Haraszti3300f742017-01-09 01:14:20 -0800996 try:
997 packet_in = self.core.packet_in_queue.get(timeout=1)
998 yield packet_in
999 except QueueEmpty:
1000 if self.stopped:
1001 break
Zsolt Haraszti66862032016-11-28 14:28:39 -08001002
1003 def send_packet_in(self, device_id, ofp_packet_in):
1004 """Must be called on the twisted thread"""
1005 packet_in = PacketIn(id=device_id, packet_in=ofp_packet_in)
1006 self.core.packet_in_queue.put(packet_in)
Zsolt Haraszti217a12e2016-12-19 16:37:55 -08001007
1008 def ReceiveChangeEvents(self, request, context):
1009 while 1:
Zsolt Haraszti3300f742017-01-09 01:14:20 -08001010 try:
1011 event = self.core.change_event_queue.get(timeout=1)
1012 yield event
1013 except QueueEmpty:
1014 if self.stopped:
1015 break
Zsolt Haraszti217a12e2016-12-19 16:37:55 -08001016
1017 def send_port_change_event(self, device_id, port_status):
1018 """Must be called on the twisted thread"""
1019 assert isinstance(port_status, ofp_port_status)
1020 event = ChangeEvent(id=device_id, port_status=port_status)
1021 self.core.change_event_queue.put(event)
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001022
1023
1024 @twisted_async
1025 def ListAlarmFilters(self, request, context):
1026 try:
1027 filters = self.root.get('/alarm_filters')
1028 return AlarmFilters(filters=filters)
1029 except KeyError:
1030 context.set_code(StatusCode.NOT_FOUND)
1031 return AlarmFilters()
1032
1033 @twisted_async
1034 def GetAlarmFilter(self, request, context):
1035 if '/' in request.id:
1036 context.set_details(
1037 'Malformed alarm filter id \'{}\''.format(request.id))
1038 context.set_code(StatusCode.INVALID_ARGUMENT)
1039 return AlarmFilter()
1040
1041 try:
1042 alarm_filter = self.root.get('/alarm_filters/{}'.format(request.id))
khenaidoo08d48d22017-06-29 19:42:49 -04001043
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001044 return alarm_filter
1045 except KeyError:
1046 context.set_details(
1047 'Alarm filter \'{}\' not found'.format(request.id))
1048 context.set_code(StatusCode.NOT_FOUND)
1049 return AlarmFilter()
1050
1051 @twisted_async
1052 def DeleteAlarmFilter(self, request, context):
1053 if '/' in request.id:
1054 context.set_details(
1055 'Malformed alarm filter id \'{}\''.format(request.id))
1056 context.set_code(StatusCode.INVALID_ARGUMENT)
1057 return Empty()
1058
1059 try:
1060 self.root.remove('/alarm_filters/{}'.format(request.id))
1061 except KeyError:
1062 context.set_code(StatusCode.NOT_FOUND)
1063
1064 return Empty()
1065
1066 @twisted_async
1067 def CreateAlarmFilter(self, request, context):
1068 log.info('grpc-request', request=request)
1069
1070 try:
1071 assert isinstance(request, AlarmFilter)
1072 alarm_filter = request
khenaidoo08d48d22017-06-29 19:42:49 -04001073 assert alarm_filter.id is not None, 'Local Alarm filter to be ' \
1074 'created must have id'
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001075 except AssertionError, e:
1076 context.set_details(e.message)
1077 context.set_code(StatusCode.INVALID_ARGUMENT)
1078 return AlarmFilter()
1079
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001080 # add device to tree
1081 self.root.add('/alarm_filters', alarm_filter)
1082
1083 return request
1084
1085 @twisted_async
1086 def UpdateAlarmFilter(self, request, context):
1087 if '/' in request.id:
1088 context.set_details(
1089 'Malformed alarm filter id \'{}\''.format(request.id))
1090 context.set_code(StatusCode.INVALID_ARGUMENT)
1091 return AlarmFilter()
1092
1093 try:
1094 assert isinstance(request, AlarmFilter)
1095 alarm_filter = self.root.get('/alarm_filters/{}'.format(request.id))
1096 self.root.update('/alarm_filters/{}'.format(request.id), request)
1097
1098 return request
1099 except KeyError:
1100 context.set_details(
1101 'Alarm filter \'{}\' not found'.format(request.id))
1102 context.set_code(StatusCode.NOT_FOUND)
1103 return AlarmFilter()
ggowdru236bd952017-06-20 20:32:55 -07001104
1105 @twisted_async
1106 def GetImages(self, request, context):
1107 log.info('grpc-request', request=request)
1108
1109 if '/' in request.id:
1110 context.set_details(
1111 'Malformed device id \'{}\''.format(request.id))
1112 context.set_code(StatusCode.INVALID_ARGUMENT)
1113 return Images()
1114
1115 try:
1116 device = self.root.get('/devices/' + request.id)
1117 return device.images
1118
1119 except KeyError:
1120 context.set_details(
1121 'Device \'{}\' not found'.format(request.id))
1122 context.set_code(StatusCode.NOT_FOUND)
1123 return Images()
sathishg5ae86222017-06-28 15:16:29 +05301124
1125 @twisted_async
1126 def SelfTest(self, request, context):
1127 log.info('grpc-request', request=request)
1128
1129 if '/' in request.id:
1130 context.set_details(
1131 'Malformed device id \'{}\''.format(request.id))
1132 context.set_code(StatusCode.INVALID_ARGUMENT)
1133 return SelfTestResponse()
1134
1135 try:
1136 path = '/devices/{}'.format(request.id)
1137 device = self.root.get(path)
1138
1139 agent = self.core.get_device_agent(device.id)
1140 resp = agent.self_test(device)
1141 return resp.result
1142
1143 except KeyError:
1144 context.set_details(
1145 'Device \'{}\' not found'.format(request.id))
1146 context.set_code(StatusCode.NOT_FOUND)
1147 return SelfTestResponse()