blob: 3aea9f1e4dc885a9c216cbd8ccd168137ed618c3 [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, \
Gamze Abaka9d343292019-02-20 06:35:18 +000028 Meters, ofp_port_status, ofp_flow_removed
Scott Bakerd865fa22018-11-07 11:45:28 -080029from voltha.protos.voltha_pb2_grpc import \
30 add_VolthaLocalServiceServicer_to_server, VolthaLocalServiceServicer
Zsolt Haraszti66862032016-11-28 14:28:39 -080031from voltha.protos.voltha_pb2 import \
Zsolt Haraszti66862032016-11-28 14:28:39 -080032 VolthaInstance, Adapters, LogicalDevices, LogicalDevice, Ports, \
Jonathan Hart8d21c322018-04-17 07:42:02 -070033 LogicalPort, LogicalPorts, Devices, Device, DeviceType, \
Stephane Barbarie4db8ca22017-04-24 10:30:20 -040034 DeviceTypes, DeviceGroups, DeviceGroup, AdminState, OperStatus, ChangeEvent, \
Stephane Barbarie2940dac2017-08-18 14:15:17 -040035 AlarmFilter, AlarmFilters, SelfTestResponse, OfAgentSubscriber
Lydia Fang01f2e852017-06-28 17:24:58 -070036from voltha.protos.device_pb2 import PmConfigs, Images, ImageDownload, ImageDownloads
Nicolas Palpacuer75ba77f2018-08-27 17:26:57 -040037from voltha.protos.common_pb2 import OperationResp, ConnectStatus
Stephane Barbarie2940dac2017-08-18 14:15:17 -040038from voltha.protos.bbf_fiber_base_pb2 import AllMulticastDistributionSetData, AllMulticastGemportsConfigData
Zsolt Haraszti66862032016-11-28 14:28:39 -080039from voltha.registry import registry
Chip Boling69abce82018-06-18 09:56:23 -050040from voltha.protos.omci_mib_db_pb2 import MibDeviceData
jasonhuang5f3e63b2018-07-27 01:32:48 +080041from voltha.protos.omci_alarm_db_pb2 import AlarmDeviceData
Nikolay Titov89004ec2017-06-19 18:22:42 -040042from requests.api import request
Stephane Barbarie2940dac2017-08-18 14:15:17 -040043from common.utils.asleep import asleep
Shad Ansariadf6c692019-04-21 00:15:15 -070044from voltha.adapters.openolt.openolt_kafka_producer import kafka_send_pb
Zsolt Haraszti66862032016-11-28 14:28:39 -080045
46log = structlog.get_logger()
47
48
49class LocalHandler(VolthaLocalServiceServicer):
khenaidoo032d3302017-06-09 14:50:04 -040050 def __init__(self, core, instance_id, core_store_id, **init_kw):
Zsolt Haraszti66862032016-11-28 14:28:39 -080051 self.core = core
khenaidoo032d3302017-06-09 14:50:04 -040052 self.instance_id = instance_id
53 self.core_store_id = core_store_id
Zsolt Haraszti66862032016-11-28 14:28:39 -080054 self.init_kw = init_kw
55 self.root = None
khenaidoo032d3302017-06-09 14:50:04 -040056 self.started_with_existing_data = False
Zsolt Haraszti66862032016-11-28 14:28:39 -080057 self.stopped = False
58
Stephane Barbarie2940dac2017-08-18 14:15:17 -040059 self.restart_delay = 2
60 self.subscriber = None
61 self.ofagent_heartbeat_count = 0
62 self.ofagent_heartbeat_max_count = 3
63 self.ofagent_heartbeat_delay = 5
64 self.ofagent_heartbeat_lc = None
65 self.ofagent_is_alive = True
66
Ryan Van Gilder5a0ab622017-03-01 16:39:25 -080067 def start(self, config_backend=None):
Zsolt Haraszti66862032016-11-28 14:28:39 -080068 log.debug('starting')
Ryan Van Gilder5a0ab622017-03-01 16:39:25 -080069 if config_backend:
70 if 'root' in config_backend:
khenaidoo032d3302017-06-09 14:50:04 -040071 # This is going to block the entire reactor until loading is
72 # completed
73 log.info('loading-config-from-persisted-backend')
74 try:
75 self.root = ConfigRoot.load(VolthaInstance,
76 kv_store=config_backend)
77 self.started_with_existing_data = True
78 except Exception, e:
79 log.exception('Failure-loading-from-backend', e=e)
Ryan Van Gilder5a0ab622017-03-01 16:39:25 -080080 else:
khenaidoo032d3302017-06-09 14:50:04 -040081 log.info('initializing-a-new-config')
Khen Nursimulud068d812017-03-06 11:44:18 -050082 self.root = ConfigRoot(VolthaInstance(**self.init_kw),
83 kv_store=config_backend)
Ryan Van Gilder5a0ab622017-03-01 16:39:25 -080084 else:
85 self.root = ConfigRoot(VolthaInstance(**self.init_kw))
86
Nikolay Titov89004ec2017-06-19 18:22:42 -040087 self.core.xpon_handler.start(self.root)
88
Zsolt Haraszti66862032016-11-28 14:28:39 -080089 log.info('started')
90 return self
91
khenaidoocbe30832017-08-25 10:43:27 -040092 def register_grpc_service(self):
93 log.debug('registering')
94 registry('grpc_server').register(
95 add_VolthaLocalServiceServicer_to_server, self)
96 log.info('registered')
97
98
Zsolt Haraszti66862032016-11-28 14:28:39 -080099 def stop(self):
100 log.debug('stopping')
101 self.stopped = True
Stephane Barbarie2940dac2017-08-18 14:15:17 -0400102
103 if self.ofagent_heartbeat_lc is not None:
104 self.ofagent_heartbeat_lc.stop()
105
106 self._ofagent_session_termination()
107
Zsolt Haraszti66862032016-11-28 14:28:39 -0800108 log.info('stopped')
109
110 def get_proxy(self, path, exclusive=False):
111 return self.root.get_proxy(path, exclusive)
112
khenaidoo032d3302017-06-09 14:50:04 -0400113 def has_started_with_existing_data(self):
114 return self.started_with_existing_data
115
Zsolt Haraszti66862032016-11-28 14:28:39 -0800116 # gRPC service method implementations. BE CAREFUL; THESE ARE CALLED ON
117 # the gRPC threadpool threads.
118
119 @twisted_async
120 def GetVolthaInstance(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400121 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800122 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
123 res = self.root.get('/', depth=depth)
124 return res
125
126 @twisted_async
127 def GetHealth(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400128 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800129 return self.root.get('/health')
130
131 @twisted_async
132 def ListAdapters(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400133 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800134 items = self.root.get('/adapters')
khenaidooc4832162017-09-20 11:55:04 -0400135 sorted_items = sorted(items, key=lambda i: i.id)
136 return Adapters(items=sorted_items)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800137
138 @twisted_async
139 def ListLogicalDevices(self, request, context):
Matteo Scandolo83dedc12018-09-16 15:11:44 +0000140 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800141 items = self.root.get('/logical_devices')
142 return LogicalDevices(items=items)
143
144 @twisted_async
Nicolas Palpacuer75ba77f2018-08-27 17:26:57 -0400145 def ListReachableLogicalDevices(self, request, context):
146 log.debug('grpc-request', request=request)
147 logical_devices = self.root.get('/logical_devices')
148 reachable_logical_devices = []
149
150 for logical_device in logical_devices:
151 device = self.root.get('/devices/{}'.format(
152 logical_device.root_device_id))
153 if device is not None and device.connect_status == \
154 ConnectStatus.REACHABLE:
155 reachable_logical_devices.append(logical_device)
156
157 return LogicalDevices(items=reachable_logical_devices)
158
159 @twisted_async
Zsolt Haraszti66862032016-11-28 14:28:39 -0800160 def GetLogicalDevice(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400161 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800162
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800163 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
164
Zsolt Haraszti66862032016-11-28 14:28:39 -0800165 if '/' in request.id:
166 context.set_details(
167 'Malformed logical device id \'{}\''.format(request.id))
168 context.set_code(StatusCode.INVALID_ARGUMENT)
169 return LogicalDevice()
170
171 try:
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800172 return self.root.get('/logical_devices/' + request.id, depth=depth)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800173 except KeyError:
174 context.set_details(
175 'Logical device \'{}\' not found'.format(request.id))
176 context.set_code(StatusCode.NOT_FOUND)
177 return LogicalDevice()
178
179 @twisted_async
180 def ListLogicalDevicePorts(self, request, context):
Matteo Scandolo83dedc12018-09-16 15:11:44 +0000181 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800182
183 if '/' in request.id:
184 context.set_details(
185 'Malformed logical device id \'{}\''.format(request.id))
186 context.set_code(StatusCode.INVALID_ARGUMENT)
187 return LogicalPorts()
188
189 try:
Khen Nursimulud068d812017-03-06 11:44:18 -0500190 items = self.root.get(
191 '/logical_devices/{}/ports'.format(request.id))
Zsolt Haraszti66862032016-11-28 14:28:39 -0800192 return LogicalPorts(items=items)
193 except KeyError:
194 context.set_details(
195 'Logical device \'{}\' not found'.format(request.id))
196 context.set_code(StatusCode.NOT_FOUND)
197 return LogicalPorts()
198
199 @twisted_async
Jonathan Hart8d21c322018-04-17 07:42:02 -0700200 def GetLogicalDevicePort(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400201 log.debug('grpc-request', requst=request)
Jonathan Hart8d21c322018-04-17 07:42:02 -0700202
203 if '/' in request.id:
204 context.set_details(
205 'Malformed logical device id \'{}\''.format(request.id))
206 context.set_code(StatusCode.INVALID_ARGUMENT)
207 return LogicalPort()
208
209 try:
210 return self.root.get(
211 '/logical_devices/{}/ports/{}'.format(request.id, request.port_id))
212 except KeyError:
213 context.set_details(
214 'Logical port \'{}\' not found on device \'{}\''.format(request.port_id, request.id))
215 context.set_code(StatusCode.NOT_FOUND)
216 return LogicalPort()
217
218 @twisted_async
Zsolt Haraszti66862032016-11-28 14:28:39 -0800219 def ListLogicalDeviceFlows(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400220 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800221
222 if '/' in request.id:
223 context.set_details(
224 'Malformed logical device id \'{}\''.format(request.id))
225 context.set_code(StatusCode.INVALID_ARGUMENT)
226 return Flows()
227
228 try:
Khen Nursimulud068d812017-03-06 11:44:18 -0500229 flows = self.root.get(
230 '/logical_devices/{}/flows'.format(request.id))
Zsolt Haraszti66862032016-11-28 14:28:39 -0800231 return flows
232 except KeyError:
233 context.set_details(
234 'Logical device \'{}\' not found'.format(request.id))
235 context.set_code(StatusCode.NOT_FOUND)
236 return Flows()
237
Zsolt Haraszti66862032016-11-28 14:28:39 -0800238 @twisted_async
Jonathan Hart8d21c322018-04-17 07:42:02 -0700239 def EnableLogicalDevicePort(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400240 log.debug('grpc-request', request=request)
Jonathan Hart8d21c322018-04-17 07:42:02 -0700241
242 if '/' in request.id:
243 context.set_details(
244 'Malformed logical device id \'{}\''.format(request.id))
245 context.set_code(StatusCode.INVALID_ARGUMENT)
246 return Empty()
247
248 try:
249 agent = self.core.get_logical_device_agent(request.id)
250 agent.port_enable(request.port_id)
251 return Empty()
252 except KeyError:
253 context.set_details(
254 'Logical device \'{}\' not found'.format(request.id))
255 context.set_code(StatusCode.NOT_FOUND)
256 return Empty()
257
258 @twisted_async
259 def DisableLogicalDevicePort(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400260 log.debug('grpc-request', request=request)
Jonathan Hart8d21c322018-04-17 07:42:02 -0700261
262 if '/' in request.id:
263 context.set_details(
264 'Malformed logical device id \'{}\''.format(request.id))
265 context.set_code(StatusCode.INVALID_ARGUMENT)
266 return Empty()
267
268 try:
269 agent = self.core.get_logical_device_agent(request.id)
270 agent.port_disable(request.port_id)
271 return Empty()
272 except KeyError:
273 context.set_details(
274 'Logical device \'{}\' not found'.format(request.id))
275 context.set_code(StatusCode.NOT_FOUND)
276 return Empty()
277
278 @twisted_async
Zsolt Haraszti66862032016-11-28 14:28:39 -0800279 def UpdateLogicalDeviceFlowTable(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400280 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800281
282 if '/' in request.id:
283 context.set_details(
284 'Malformed logical device id \'{}\''.format(request.id))
285 context.set_code(StatusCode.INVALID_ARGUMENT)
286 return Empty()
287
288 try:
289 agent = self.core.get_logical_device_agent(request.id)
290 agent.update_flow_table(request.flow_mod)
291 return Empty()
292 except KeyError:
293 context.set_details(
294 'Logical device \'{}\' not found'.format(request.id))
295 context.set_code(StatusCode.NOT_FOUND)
296 return Empty()
297
298 @twisted_async
299 def ListLogicalDeviceFlowGroups(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400300 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800301
302 if '/' in request.id:
303 context.set_details(
304 'Malformed logical device id \'{}\''.format(request.id))
305 context.set_code(StatusCode.INVALID_ARGUMENT)
306 return FlowGroups()
307
308 try:
309 groups = self.root.get(
310 '/logical_devices/{}/flow_groups'.format(request.id))
311 return groups
312 except KeyError:
313 context.set_details(
314 'Logical device \'{}\' not found'.format(request.id))
315 context.set_code(StatusCode.NOT_FOUND)
316 return FlowGroups()
317
318 @twisted_async
319 def UpdateLogicalDeviceFlowGroupTable(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400320 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800321
322 if '/' in request.id:
323 context.set_details(
324 'Malformed logical device id \'{}\''.format(request.id))
325 context.set_code(StatusCode.INVALID_ARGUMENT)
326 return Empty()
327
328 try:
329 agent = self.core.get_logical_device_agent(request.id)
330 agent.update_group_table(request.group_mod)
331 return Empty()
332 except KeyError:
333 context.set_details(
334 'Logical device \'{}\' not found'.format(request.id))
335 context.set_code(StatusCode.NOT_FOUND)
336 return Empty()
337
338 @twisted_async
339 def ListDevices(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400340 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800341 items = self.root.get('/devices')
342 return Devices(items=items)
343
344 @twisted_async
345 def GetDevice(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400346 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800347
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800348 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
349
Zsolt Haraszti66862032016-11-28 14:28:39 -0800350 if '/' in request.id:
351 context.set_details(
352 'Malformed device id \'{}\''.format(request.id))
353 context.set_code(StatusCode.INVALID_ARGUMENT)
354 return Device()
355
356 try:
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800357 return self.root.get('/devices/' + request.id, depth=depth)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800358 except KeyError:
359 context.set_details(
360 'Device \'{}\' not found'.format(request.id))
361 context.set_code(StatusCode.NOT_FOUND)
362 return Device()
363
364 @twisted_async
365 def CreateDevice(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400366 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800367
368 known_device_types = dict(
369 (dt.id, dt) for dt in self.root.get('/device_types'))
Nikolay Titovff35fb32017-09-24 13:33:29 -0400370 known_devices = self.root.get('/devices')
Zsolt Haraszti66862032016-11-28 14:28:39 -0800371
372 try:
373 assert isinstance(request, Device)
374 device = request
375 assert device.id == '', 'Device to be created cannot have id yet'
376 assert device.type in known_device_types, \
377 'Unknown device type \'{}\''.format(device.type)
378 assert device.admin_state in (AdminState.UNKNOWN,
379 AdminState.PREPROVISIONED), \
380 'Newly created device cannot be ' \
381 'in admin state \'{}\''.format(device.admin_state)
Nikolay Titovff35fb32017-09-24 13:33:29 -0400382 assert device.WhichOneof("address") is not None, \
383 'Device must have one contact address e.g. MAC, IPv4, IPv6, H&P'
384 error_message = 'Device with {} address \'{}\' already exists'
385 for _device in known_devices:
386 if _device.HasField(device.WhichOneof("address")):
387 if device.HasField("mac_address"):
388 assert device.mac_address != _device.mac_address, \
389 error_message.format('MAC', device.mac_address)
390 elif device.HasField("ipv4_address"):
391 assert device.ipv4_address != _device.ipv4_address, \
392 error_message.format('IPv4', device.ipv4_address)
393 elif device.HasField("ipv6_address"):
394 assert device.ipv6_address != _device.ipv6_address, \
395 error_message.format('IPv6', device.ipv6_address)
396 elif device.HasField("host_and_port"):
397 assert device.host_and_port != _device.host_and_port, \
398 error_message.format('Host and Port',
399 device.host_and_port)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800400 except AssertionError, e:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400401 context.set_details(e.message)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800402 context.set_code(StatusCode.INVALID_ARGUMENT)
403 return Device()
404
405 # fill additional data
khenaidooa8588f22017-06-16 12:13:34 -0400406 device.id = create_cluster_device_id(self.core_store_id)
407 log.debug('device-id-created', device_id=device.id)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800408 device_type = known_device_types[device.type]
409 device.adapter = device_type.adapter
410 if device.admin_state != AdminState.PREPROVISIONED:
411 device.admin_state = AdminState.PREPROVISIONED
412 device.oper_status = OperStatus.UNKNOWN
Niren R Chidrawara5753632017-08-31 03:18:03 -0400413 device.vendor_id = device_type.vendor_id
Zsolt Haraszti66862032016-11-28 14:28:39 -0800414
415 # add device to tree
416 self.root.add('/devices', device)
417
418 return request
419
420 @twisted_async
Khen Nursimulud068d812017-03-06 11:44:18 -0500421 def EnableDevice(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400422 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800423
424 if '/' in request.id:
425 context.set_details(
426 'Malformed device id \'{}\''.format(request.id))
427 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400428 return Empty()
Zsolt Haraszti66862032016-11-28 14:28:39 -0800429
430 try:
431 path = '/devices/{}'.format(request.id)
432 device = self.root.get(path)
Khen Nursimulud068d812017-03-06 11:44:18 -0500433 assert device.admin_state in (AdminState.PREPROVISIONED,
434 AdminState.DISABLED), \
435 'Device to enable cannot be ' \
436 'in admin state \'{}\''.format(device.admin_state)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800437 device.admin_state = AdminState.ENABLED
438 self.root.update(path, device, strict=True)
439
Khen Nursimulud068d812017-03-06 11:44:18 -0500440 except AssertionError, e:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400441 context.set_details(e.message)
Khen Nursimulud068d812017-03-06 11:44:18 -0500442 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimulud068d812017-03-06 11:44:18 -0500443
444 except KeyError:
445 context.set_details(
446 'Device \'{}\' not found'.format(request.id))
447 context.set_code(StatusCode.NOT_FOUND)
448
449 return Empty()
450
451 @twisted_async
452 def DisableDevice(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400453 log.debug('grpc-request', request=request)
Khen Nursimulud068d812017-03-06 11:44:18 -0500454
455 if '/' in request.id:
456 context.set_details(
457 'Malformed device id \'{}\''.format(request.id))
458 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400459 return Empty()
Khen Nursimulud068d812017-03-06 11:44:18 -0500460 try:
461 path = '/devices/{}'.format(request.id)
462 device = self.root.get(path)
463 assert device.admin_state == AdminState.ENABLED, \
464 'Device to disable cannot be ' \
465 'in admin state \'{}\''.format(device.admin_state)
466 device.admin_state = AdminState.DISABLED
467 self.root.update(path, device, strict=True)
468
469 except AssertionError, e:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400470 context.set_details(e.message)
Khen Nursimulud068d812017-03-06 11:44:18 -0500471 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimulud068d812017-03-06 11:44:18 -0500472
473 except KeyError:
474 context.set_details(
475 'Device \'{}\' not found'.format(request.id))
476 context.set_code(StatusCode.NOT_FOUND)
477
khenaidoo032d3302017-06-09 14:50:04 -0400478 except Exception, e:
479 log.exception('disable-exception', e=e)
480
Khen Nursimulud068d812017-03-06 11:44:18 -0500481 return Empty()
482
483 @twisted_async
484 def RebootDevice(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400485 log.debug('grpc-request', request=request)
Khen Nursimulud068d812017-03-06 11:44:18 -0500486
487 if '/' in request.id:
488 context.set_details(
489 'Malformed device id \'{}\''.format(request.id))
490 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400491 return Empty()
Khen Nursimulud068d812017-03-06 11:44:18 -0500492
493 try:
494 path = '/devices/{}'.format(request.id)
495 device = self.root.get(path)
Lydia Fang01f2e852017-06-28 17:24:58 -0700496 assert device.admin_state != AdminState.DOWNLOADING_IMAGE, \
497 'Device to reboot cannot be ' \
498 'in admin state \'{}\''.format(device.admin_state)
Khen Nursimulud068d812017-03-06 11:44:18 -0500499 agent = self.core.get_device_agent(device.id)
500 agent.reboot_device(device)
501
Khen Nursimulud068d812017-03-06 11:44:18 -0500502 except KeyError:
503 context.set_details(
504 'Device \'{}\' not found'.format(request.id))
505 context.set_code(StatusCode.NOT_FOUND)
506
507 return Empty()
508
509 @twisted_async
Lydia Fang01f2e852017-06-28 17:24:58 -0700510 def DownloadImage(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400511 log.debug('grpc-request', request=request)
Lydia Fang01f2e852017-06-28 17:24:58 -0700512
513 if '/' in request.id:
514 context.set_details(
515 'Malformed device id \'{}\''.format(request.id))
516 context.set_code(StatusCode.INVALID_ARGUMENT)
517 return OperationResp(code=OperationResp.OPERATION_FAILURE)
518
519 try:
520 path = '/devices/{}'.format(request.id)
521 device = self.root.get(path)
522 assert isinstance(request, ImageDownload)
523 self.root.add('/devices/{}/image_downloads'.\
524 format(request.id), request)
lcuie3aefd92019-01-02 22:50:32 -0800525 # assert device.admin_state == AdminState.ENABLED, \
526 # 'Device to DOWNLOADING_IMAGE cannot be ' \
527 # 'in admin state \'{}\''.format(device.admin_state)
Lydia Fang01f2e852017-06-28 17:24:58 -0700528 device.admin_state = AdminState.DOWNLOADING_IMAGE
529 self.root.update(path, device, strict=True)
530 agent = self.core.get_device_agent(device.id)
531 agent.register_image_download(request)
532 return OperationResp(code=OperationResp.OPERATION_SUCCESS)
533
534 except AssertionError as e:
535 context.set_details(e.message)
536 context.set_code(StatusCode.INVALID_ARGUMENT)
537 return OperationResp(code=OperationResp.OPERATION_UNSUPPORTED)
538
539 except KeyError:
540 context.set_details(
541 'Device \'{}\' not found'.format(request.id))
542 context.set_code(StatusCode.NOT_FOUND)
543 return OperationResp(code=OperationResp.OPERATION_FAILURE)
544
545 except Exception as e:
546 log.exception(e.message)
547 context.set_code(StatusCode.NOT_FOUND)
548 return OperationResp(code=OperationResp.OPERATION_FAILURE)
549
550 @twisted_async
551 def GetImageDownloadStatus(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400552 log.debug('grpc-request', request=request)
Lydia Fang01f2e852017-06-28 17:24:58 -0700553
554 if '/' in request.id:
555 context.set_details(
556 'Malformed device id \'{}\''.format(request.id))
557 context.set_code(StatusCode.INVALID_ARGUMENT)
558 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
559 return response
560
561 try:
562 path = '/devices/{}'.format(request.id)
563 device = self.root.get(path)
564 agent = self.core.get_device_agent(device.id)
565 img_dnld = self.root.get('/devices/{}/image_downloads/{}'.\
566 format(request.id, request.name))
lcui33d6a8e2018-08-28 12:51:38 -0700567 response = agent.get_image_download_status(img_dnld)
568 #try:
569 # response = self.root.get('/devices/{}/image_downloads/{}'.\
570 # format(request.id, request.name))
571 #except Exception as e:
572 # log.exception(e.message)
Lydia Fang01f2e852017-06-28 17:24:58 -0700573 return response
574
575 except KeyError:
576 context.set_details(
577 'Device \'{}\' not found'.format(request.id))
578 context.set_code(StatusCode.NOT_FOUND)
579 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
580 return response
581 except Exception as e:
582 log.exception(e.message)
583 response = ImageDownload(state=ImageDownload.DOWNLOAD_FAILED)
584 return response
585
586 @twisted_async
587 def GetImageDownload(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400588 log.debug('grpc-request', request=request)
Lydia Fang01f2e852017-06-28 17:24:58 -0700589
590 if '/' in request.id:
591 context.set_details(
592 'Malformed device id \'{}\''.format(request.id))
593 context.set_code(StatusCode.INVALID_ARGUMENT)
594 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
595 return response
596
597 try:
598 response = self.root.get('/devices/{}/image_downloads/{}'.\
599 format(request.id, request.name))
600 return response
601
602 except KeyError:
603 context.set_details(
604 'Device \'{}\' not found'.format(request.id))
605 context.set_code(StatusCode.NOT_FOUND)
606 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
607 return response
608
609 @twisted_async
610 def ListImageDownloads(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400611 log.debug('grpc-request', request=request)
Lydia Fang01f2e852017-06-28 17:24:58 -0700612
613 if '/' in request.id:
614 context.set_details(
615 'Malformed device id \'{}\''.format(request.id))
616 context.set_code(StatusCode.INVALID_ARGUMENT)
617 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
618 return response
619
620 try:
621 response = self.root.get('/devices/{}/image_downloads'.\
622 format(request.id))
623 return ImageDownloads(items=response)
624
625 except KeyError:
626 context.set_details(
627 'Device \'{}\' not found'.format(request.id))
628 context.set_code(StatusCode.NOT_FOUND)
629 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
630 return response
631
632 @twisted_async
633 def CancelImageDownload(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400634 log.debug('grpc-request', request=request)
Lydia Fang01f2e852017-06-28 17:24:58 -0700635
636 if '/' in request.id:
637 context.set_details(
638 'Malformed device id \'{}\''.format(request.id))
639 context.set_code(StatusCode.INVALID_ARGUMENT)
640 return OperationResp(code=OperationResp.OPERATION_FAILURE)
641
642 try:
643 assert isinstance(request, ImageDownload)
644 path = '/devices/{}'.format(request.id)
645 device = self.root.get(path)
lcui33d6a8e2018-08-28 12:51:38 -0700646 # assert device.admin_state == AdminState.DOWNLOADING_IMAGE, \
647 # 'Device to cancel DOWNLOADING_IMAGE cannot be ' \
648 # 'in admin state \'{}\''.format(device.admin_state)
Lydia Fang01f2e852017-06-28 17:24:58 -0700649 agent = self.core.get_device_agent(device.id)
650 agent.cancel_image_download(request)
lcui33d6a8e2018-08-28 12:51:38 -0700651 self.root.remove('/devices/{}/image_downloads/{}'.format(request.id, request.name))
652
Lydia Fang01f2e852017-06-28 17:24:58 -0700653 return OperationResp(code=OperationResp.OPERATION_SUCCESS)
654
655 except KeyError:
656 context.set_details(
657 'Device \'{}\' not found'.format(request.id))
658 context.set_code(StatusCode.NOT_FOUND)
659 return OperationResp(code=OperationResp.OPERATION_FAILURE)
660
661 @twisted_async
662 def ActivateImageUpdate(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400663 log.debug('grpc-request', request=request)
Lydia Fang01f2e852017-06-28 17:24:58 -0700664
665 if '/' in request.id:
666 context.set_details(
667 'Malformed device id \'{}\''.format(request.id))
668 context.set_code(StatusCode.INVALID_ARGUMENT)
669 return OperationResp(code=OperationResp.OPERATION_FAILURE)
670
671 try:
672 assert isinstance(request, ImageDownload)
673 path = '/devices/{}'.format(request.id)
674 device = self.root.get(path)
lcuie3aefd92019-01-02 22:50:32 -0800675 assert device.admin_state == AdminState.ENABLED, \
676 'Device to activate image cannot be ' \
677 'in admin state \'{}\''.format(device.admin_state)
Lydia Fang01f2e852017-06-28 17:24:58 -0700678 agent = self.core.get_device_agent(device.id)
679 agent.activate_image_update(request)
680 return OperationResp(code=OperationResp.OPERATION_SUCCESS)
681
682 except KeyError:
683 context.set_details(
684 'Device \'{}\' not found'.format(request.id))
685 context.set_code(StatusCode.NOT_FOUND)
686 return OperationResp(code=OperationResp.OPERATION_FAILURE)
687
688 @twisted_async
689 def RevertImageUpdate(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400690 log.debug('grpc-request', request=request)
Lydia Fang01f2e852017-06-28 17:24:58 -0700691
692 if '/' in request.id:
693 context.set_details(
694 'Malformed device id \'{}\''.format(request.id))
695 context.set_code(StatusCode.INVALID_ARGUMENT)
696 return OperationResp(code=OperationResp.OPERATION_FAILURE)
697
698 try:
699 assert isinstance(request, ImageDownload)
700 path = '/devices/{}'.format(request.id)
701 device = self.root.get(path)
702 assert device.admin_state == AdminState.ENABLED, \
703 'Device to revert image cannot be ' \
704 'in admin state \'{}\''.format(device.admin_state)
705 agent = self.core.get_device_agent(device.id)
706 agent.revert_image_update(request)
707 return OperationResp(code=OperationResp.OPERATION_SUCCESS)
708
709 except KeyError:
710 context.set_details(
711 'Device \'{}\' not found'.format(request.id))
712 context.set_code(StatusCode.NOT_FOUND)
713 return OperationResp(code=OperationResp.OPERATION_FAILURE)
714
715 @twisted_async
Khen Nursimulud068d812017-03-06 11:44:18 -0500716 def DeleteDevice(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400717 log.debug('grpc-request', request=request)
Khen Nursimulud068d812017-03-06 11:44:18 -0500718
719 if '/' in request.id:
720 context.set_details(
721 'Malformed device id \'{}\''.format(request.id))
722 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400723 return Empty()
Khen Nursimulud068d812017-03-06 11:44:18 -0500724
725 try:
726 path = '/devices/{}'.format(request.id)
727 device = self.root.get(path)
Venkata Telu41e72862018-06-11 11:54:43 -0500728 assert device.admin_state == AdminState.DISABLED or device.admin_state == AdminState.PREPROVISIONED, \
Khen Nursimulud068d812017-03-06 11:44:18 -0500729 'Device to delete cannot be ' \
730 'in admin state \'{}\''.format(device.admin_state)
731
732 self.root.remove(path)
733
734 except AssertionError, e:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400735 context.set_details(e.message)
Khen Nursimulud068d812017-03-06 11:44:18 -0500736 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimulud068d812017-03-06 11:44:18 -0500737
Zsolt Haraszti66862032016-11-28 14:28:39 -0800738 except KeyError:
739 context.set_details(
740 'Device \'{}\' not found'.format(request.id))
741 context.set_code(StatusCode.NOT_FOUND)
742
743 return Empty()
744
745 @twisted_async
746 def ListDevicePorts(self, request, context):
Matteo Scandolo83dedc12018-09-16 15:11:44 +0000747 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800748
749 if '/' in request.id:
750 context.set_details(
751 'Malformed device id \'{}\''.format(request.id))
752 context.set_code(StatusCode.INVALID_ARGUMENT)
753 return Ports()
754
755 try:
756 items = self.root.get('/devices/{}/ports'.format(request.id))
757 return Ports(items=items)
758 except KeyError:
759 context.set_details(
760 'Device \'{}\' not found'.format(request.id))
761 context.set_code(StatusCode.NOT_FOUND)
762 return Ports()
763
Sergio Slobodriana2eb52b2017-03-07 12:24:46 -0500764 @twisted_async
765 def ListDevicePmConfigs(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400766 log.debug('grpc-request', request=request)
Sergio Slobodriana2eb52b2017-03-07 12:24:46 -0500767
Sergio Slobodrian71960022017-03-09 10:20:57 -0500768 if '/' in request.id:
769 context.set_details(
770 'Malformed device id \'{}\''.format(request.id))
771 context.set_code(StatusCode.INVALID_ARGUMENT)
772 return PmConfigs()
773
774 try:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400775 pm_configs = self.root.get(
776 '/devices/{}/pm_configs'.format(request.id))
Sergio Slobodrian2db4c102017-03-09 22:29:23 -0500777 pm_configs.id = request.id
khenaidoo5431e4c2017-08-17 15:05:40 -0400778 log.debug('device-for-pms', pm_configs=pm_configs)
Sergio Slobodrian2db4c102017-03-09 22:29:23 -0500779 return pm_configs
Sergio Slobodrian71960022017-03-09 10:20:57 -0500780 except KeyError:
781 context.set_details(
782 'Device \'{}\' not found'.format(request.id))
783 context.set_code(StatusCode.NOT_FOUND)
784 return PmConfigs()
785
Sergio Slobodriana2eb52b2017-03-07 12:24:46 -0500786 @twisted_async
787 def UpdateDevicePmConfigs(self, request, context):
khenaidoo5431e4c2017-08-17 15:05:40 -0400788 log.debug('grpc-request', request=request)
Sergio Slobodrian2db4c102017-03-09 22:29:23 -0500789
790 if '/' in request.id:
791 context.set_details(
792 'Malformed logical device id \'{}\''.format(request.id))
793 context.set_code(StatusCode.INVALID_ARGUMENT)
794 return Empty()
795
796 try:
797 device = self.root.get('/devices/{}'.format(request.id))
798 agent = self.core.get_device_agent(request.id)
799 agent.update_device_pm_config(request)
800 return Empty()
801 except KeyError:
802 context.set_details(
803 'Device \'{}\' not found'.format(request.id))
804 context.set_code(StatusCode.NOT_FOUND)
805 return Empty()
Sergio Slobodriana2eb52b2017-03-07 12:24:46 -0500806
Zsolt Haraszti66862032016-11-28 14:28:39 -0800807 @twisted_async
808 def ListDeviceFlows(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400809 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800810
811 if '/' in request.id:
812 context.set_details(
813 'Malformed device id \'{}\''.format(request.id))
814 context.set_code(StatusCode.INVALID_ARGUMENT)
815 return Flows()
816
817 try:
818 flows = self.root.get('/devices/{}/flows'.format(request.id))
819 return flows
820 except KeyError:
821 context.set_details(
822 'Device \'{}\' not found'.format(request.id))
823 context.set_code(StatusCode.NOT_FOUND)
824 return Flows()
825
Zsolt Haraszti66862032016-11-28 14:28:39 -0800826 @twisted_async
827 def ListDeviceFlowGroups(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400828 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800829
830 if '/' in request.id:
831 context.set_details(
832 'Malformed device id \'{}\''.format(request.id))
833 context.set_code(StatusCode.INVALID_ARGUMENT)
834 return FlowGroups()
835
836 try:
Khen Nursimulud068d812017-03-06 11:44:18 -0500837 groups = self.root.get(
838 '/devices/{}/flow_groups'.format(request.id))
Zsolt Haraszti66862032016-11-28 14:28:39 -0800839 return groups
840 except KeyError:
841 context.set_details(
842 'Device \'{}\' not found'.format(request.id))
843 context.set_code(StatusCode.NOT_FOUND)
844 return FlowGroups()
845
846 @twisted_async
847 def ListDeviceTypes(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400848 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800849 items = self.root.get('/device_types')
khenaidooc4832162017-09-20 11:55:04 -0400850 sorted_items = sorted(items, key=lambda i: i.id)
851 return DeviceTypes(items=sorted_items)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800852
853 @twisted_async
854 def GetDeviceType(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400855 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800856
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800857 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
858
Zsolt Haraszti66862032016-11-28 14:28:39 -0800859 if '/' in request.id:
860 context.set_details(
861 'Malformed device type id \'{}\''.format(request.id))
862 context.set_code(StatusCode.INVALID_ARGUMENT)
863 return DeviceType()
864
865 try:
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800866 return self.root.get('/device_types/' + request.id, depth=depth)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800867 except KeyError:
868 context.set_details(
869 'Device type \'{}\' not found'.format(request.id))
870 context.set_code(StatusCode.NOT_FOUND)
871 return DeviceType()
872
873 @twisted_async
874 def ListDeviceGroups(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400875 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800876 # TODO is this mapped to tree or taken from coordinator?
877 items = self.root.get('/device_groups')
878 return DeviceGroups(items=items)
879
880 @twisted_async
881 def GetDeviceGroup(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400882 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800883
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800884 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
885
Zsolt Haraszti66862032016-11-28 14:28:39 -0800886 if '/' in request.id:
887 context.set_details(
888 'Malformed device group id \'{}\''.format(request.id))
889 context.set_code(StatusCode.INVALID_ARGUMENT)
890 return DeviceGroup()
891
892 # TODO is this mapped to tree or taken from coordinator?
893 try:
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800894 return self.root.get('/device_groups/' + request.id, depth=depth)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800895 except KeyError:
896 context.set_details(
897 'Device group \'{}\' not found'.format(request.id))
898 context.set_code(StatusCode.NOT_FOUND)
899 return DeviceGroup()
900
Nikolay Titov89004ec2017-06-19 18:22:42 -0400901 # bbf_fiber rpcs start
902 @twisted_async
903 def GetAllChannelgroupConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400904 return self.core.xpon_handler.get_all_channel_group_config(
905 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400906
907 @twisted_async
908 def CreateChannelgroup(self, request, context):
909 return self.core.xpon_handler.create_channel_group(request, context)
910
911 @twisted_async
912 def UpdateChannelgroup(self, request, context):
913 return self.core.xpon_handler.update_channel_group(request, context)
914
915 @twisted_async
916 def DeleteChannelgroup(self, request, context):
917 return self.core.xpon_handler.delete_channel_group(request, context)
918
919 @twisted_async
920 def GetAllChannelpartitionConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400921 return self.core.xpon_handler.get_all_channel_partition_config(
922 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400923
924 @twisted_async
925 def CreateChannelpartition(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400926 return self.core.xpon_handler.create_channel_partition(
927 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400928
929 @twisted_async
930 def UpdateChannelpartition(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400931 return self.core.xpon_handler.update_channel_partition(
932 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400933
934 @twisted_async
935 def DeleteChannelpartition(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400936 return self.core.xpon_handler.delete_channel_partition(
937 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400938
939 @twisted_async
940 def GetAllChannelpairConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400941 return self.core.xpon_handler.get_all_channel_pair_config(
942 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400943
944 @twisted_async
945 def CreateChannelpair(self, request, context):
946 return self.core.xpon_handler.create_channel_pair(request, context)
947
948 @twisted_async
949 def UpdateChannelpair(self, request, context):
950 return self.core.xpon_handler.update_channel_pair(request, context)
951
952 @twisted_async
953 def DeleteChannelpair(self, request, context):
954 return self.core.xpon_handler.delete_channel_pair(request, context)
955
956 @twisted_async
957 def GetAllChannelterminationConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400958 return self.core.xpon_handler.get_all_channel_termination_config(
959 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400960
961 @twisted_async
962 def CreateChanneltermination(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400963 return self.core.xpon_handler.create_channel_termination(
964 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400965
966 @twisted_async
967 def UpdateChanneltermination(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400968 return self.core.xpon_handler.update_channel_termination(
969 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400970
971 @twisted_async
972 def DeleteChanneltermination(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400973 return self.core.xpon_handler.delete_channel_termination(
974 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400975
976 @twisted_async
977 def GetAllOntaniConfig(self, request, context):
978 return self.core.xpon_handler.get_all_ont_ani_config(request, context)
979
980 @twisted_async
981 def CreateOntani(self, request, context):
982 return self.core.xpon_handler.create_ont_ani(request, context)
983
984 @twisted_async
985 def UpdateOntani(self, request, context):
986 return self.core.xpon_handler.update_ont_ani(request, context)
987
988 @twisted_async
989 def DeleteOntani(self, request, context):
990 return self.core.xpon_handler.delete_ont_ani(request, context)
991
992 @twisted_async
993 def GetAllVOntaniConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400994 return self.core.xpon_handler.get_all_v_ont_ani_config(
995 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400996
997 @twisted_async
998 def CreateVOntani(self, request, context):
999 return self.core.xpon_handler.create_v_ont_ani(request, context)
1000
1001 @twisted_async
1002 def UpdateVOntani(self, request, context):
1003 return self.core.xpon_handler.update_v_ont_ani(request, context)
1004
1005 @twisted_async
1006 def DeleteVOntani(self, request, context):
1007 return self.core.xpon_handler.delete_v_ont_ani(request, context)
1008
1009 @twisted_async
1010 def GetAllVEnetConfig(self, request, context):
1011 return self.core.xpon_handler.get_all_v_enet_config(request, context)
1012
1013 @twisted_async
1014 def CreateVEnet(self, request, context):
1015 return self.core.xpon_handler.create_v_enet(request, context)
1016
1017 @twisted_async
1018 def UpdateVEnet(self, request, context):
1019 return self.core.xpon_handler.update_v_enet(request, context)
1020
1021 @twisted_async
1022 def DeleteVEnet(self, request, context):
1023 return self.core.xpon_handler.delete_v_enet(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001024
1025 @twisted_async
1026 def GetAllTrafficDescriptorProfileData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001027 return self.core.xpon_handler.get_all_traffic_descriptor_profile_data(
1028 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001029
1030 @twisted_async
1031 def CreateTrafficDescriptorProfileData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001032 return self.core.xpon_handler.create_traffic_descriptor_profile(
1033 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001034
1035 @twisted_async
1036 def UpdateTrafficDescriptorProfileData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001037 return self.core.xpon_handler.update_traffic_descriptor_profile(
1038 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001039
1040 @twisted_async
1041 def DeleteTrafficDescriptorProfileData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001042 return self.core.xpon_handler.delete_traffic_descriptor_profile(
1043 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001044
1045 @twisted_async
1046 def GetAllTcontsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001047 return self.core.xpon_handler.get_all_tconts_config_data(
1048 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001049
1050 @twisted_async
1051 def CreateTcontsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001052 return self.core.xpon_handler.create_tcont(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001053
1054 @twisted_async
1055 def UpdateTcontsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001056 return self.core.xpon_handler.update_tcont(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001057
1058 @twisted_async
1059 def DeleteTcontsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001060 return self.core.xpon_handler.delete_tcont(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001061
1062 @twisted_async
1063 def GetAllGemportsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001064 return self.core.xpon_handler.get_all_gemports_config_data(
1065 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001066
1067 @twisted_async
1068 def CreateGemportsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001069 return self.core.xpon_handler.create_gem_port(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001070
1071 @twisted_async
1072 def UpdateGemportsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001073 return self.core.xpon_handler.update_gem_port(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001074
1075 @twisted_async
1076 def DeleteGemportsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001077 return self.core.xpon_handler.delete_gem_port(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001078
1079 @twisted_async
1080 def GetAllMulticastGemportsConfigData(self, request, context):
1081 return AllMulticastGemportsConfigData()
1082
1083 @twisted_async
1084 def CreateMulticastGemportsConfigData(self, request, context):
1085 return Empty()
1086
1087 @twisted_async
1088 def UpdateMulticastGemportsConfigData(self, request, context):
1089 return Empty()
1090
1091 @twisted_async
1092 def DeleteMulticastGemportsConfigData(self, request, context):
1093 return Empty()
1094
1095 @twisted_async
1096 def GetAllMulticastDistributionSetData(self, request, context):
1097 return AllMulticastDistributionSetData()
1098
1099 @twisted_async
1100 def CreateMulticastDistributionSetData(self, request, context):
1101 return Empty()
1102
1103 @twisted_async
1104 def UpdateMulticastDistributionSetData(self, request, context):
1105 return Empty()
1106
1107 @twisted_async
1108 def DeleteMulticastDistributionSetData(self, request, context):
1109 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -04001110 # bbf_fiber rpcs end
1111
Zsolt Haraszti66862032016-11-28 14:28:39 -08001112 def StreamPacketsOut(self, request_iterator, context):
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001113 log.debug('start-stream-packets-out')
Zsolt Haraszti66862032016-11-28 14:28:39 -08001114
1115 @twisted_async
1116 def forward_packet_out(packet_out):
1117 agent = self.core.get_logical_device_agent(packet_out.id)
1118 agent.packet_out(packet_out.packet_out)
1119
Shad Ansari42392a72019-04-09 22:44:18 -07001120 for req in request_iterator:
1121 device_agent = self.core.get_logical_device_agent(req.id)
1122 adapter_name = device_agent.device_adapter_agent.name
1123
1124 if adapter_name == 'openolt':
1125 log.debug('fast path pkt-out to kafka')
Shad Ansaria3bcfe12019-04-13 11:46:28 -07001126 kafka_send_pb('voltha.pktout-{}'.format(req.id), req)
Shad Ansari42392a72019-04-09 22:44:18 -07001127 else:
1128 forward_packet_out(packet_out=req)
Zsolt Haraszti66862032016-11-28 14:28:39 -08001129
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001130 log.debug('stop-stream-packets-out')
1131
Zsolt Haraszti66862032016-11-28 14:28:39 -08001132 return Empty()
1133
1134 def ReceivePacketsIn(self, request, context):
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001135 log.debug('start-receive-packets-in')
1136 while self.ofagent_is_alive:
Zsolt Haraszti3300f742017-01-09 01:14:20 -08001137 try:
1138 packet_in = self.core.packet_in_queue.get(timeout=1)
1139 yield packet_in
1140 except QueueEmpty:
1141 if self.stopped:
1142 break
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001143 log.debug('stop-receive-packets-in')
Zsolt Haraszti66862032016-11-28 14:28:39 -08001144
1145 def send_packet_in(self, device_id, ofp_packet_in):
1146 """Must be called on the twisted thread"""
1147 packet_in = PacketIn(id=device_id, packet_in=ofp_packet_in)
1148 self.core.packet_in_queue.put(packet_in)
Zsolt Haraszti217a12e2016-12-19 16:37:55 -08001149
1150 def ReceiveChangeEvents(self, request, context):
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001151 log.debug('start-receive-change-events')
1152 while self.ofagent_is_alive:
Zsolt Haraszti3300f742017-01-09 01:14:20 -08001153 try:
1154 event = self.core.change_event_queue.get(timeout=1)
1155 yield event
1156 except QueueEmpty:
1157 if self.stopped:
1158 break
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001159 log.debug('stop-receive-change-events')
Zsolt Haraszti217a12e2016-12-19 16:37:55 -08001160
1161 def send_port_change_event(self, device_id, port_status):
1162 """Must be called on the twisted thread"""
1163 assert isinstance(port_status, ofp_port_status)
1164 event = ChangeEvent(id=device_id, port_status=port_status)
1165 self.core.change_event_queue.put(event)
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001166
Gamze Abaka9d343292019-02-20 06:35:18 +00001167 def send_flow_removed_event(self, device_id, flow_removed):
1168 assert isinstance(flow_removed, ofp_flow_removed)
1169 event = ChangeEvent(id=device_id, flow_removed=flow_removed)
1170 self.core.change_event_queue.put(event)
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001171
1172 @twisted_async
1173 def ListAlarmFilters(self, request, context):
1174 try:
1175 filters = self.root.get('/alarm_filters')
1176 return AlarmFilters(filters=filters)
1177 except KeyError:
1178 context.set_code(StatusCode.NOT_FOUND)
1179 return AlarmFilters()
1180
1181 @twisted_async
1182 def GetAlarmFilter(self, request, context):
1183 if '/' in request.id:
1184 context.set_details(
1185 'Malformed alarm filter id \'{}\''.format(request.id))
1186 context.set_code(StatusCode.INVALID_ARGUMENT)
1187 return AlarmFilter()
1188
1189 try:
1190 alarm_filter = self.root.get('/alarm_filters/{}'.format(request.id))
khenaidoo08d48d22017-06-29 19:42:49 -04001191
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001192 return alarm_filter
1193 except KeyError:
1194 context.set_details(
1195 'Alarm filter \'{}\' not found'.format(request.id))
1196 context.set_code(StatusCode.NOT_FOUND)
1197 return AlarmFilter()
1198
1199 @twisted_async
1200 def DeleteAlarmFilter(self, request, context):
1201 if '/' in request.id:
1202 context.set_details(
1203 'Malformed alarm filter id \'{}\''.format(request.id))
1204 context.set_code(StatusCode.INVALID_ARGUMENT)
1205 return Empty()
1206
1207 try:
1208 self.root.remove('/alarm_filters/{}'.format(request.id))
1209 except KeyError:
1210 context.set_code(StatusCode.NOT_FOUND)
1211
1212 return Empty()
1213
1214 @twisted_async
1215 def CreateAlarmFilter(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -04001216 log.debug('grpc-request', request=request)
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001217
1218 try:
1219 assert isinstance(request, AlarmFilter)
1220 alarm_filter = request
khenaidoo08d48d22017-06-29 19:42:49 -04001221 assert alarm_filter.id is not None, 'Local Alarm filter to be ' \
1222 'created must have id'
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001223 except AssertionError, e:
1224 context.set_details(e.message)
1225 context.set_code(StatusCode.INVALID_ARGUMENT)
1226 return AlarmFilter()
1227
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001228 # add device to tree
1229 self.root.add('/alarm_filters', alarm_filter)
1230
1231 return request
1232
1233 @twisted_async
1234 def UpdateAlarmFilter(self, request, context):
1235 if '/' in request.id:
1236 context.set_details(
1237 'Malformed alarm filter id \'{}\''.format(request.id))
1238 context.set_code(StatusCode.INVALID_ARGUMENT)
1239 return AlarmFilter()
1240
1241 try:
1242 assert isinstance(request, AlarmFilter)
1243 alarm_filter = self.root.get('/alarm_filters/{}'.format(request.id))
1244 self.root.update('/alarm_filters/{}'.format(request.id), request)
1245
1246 return request
1247 except KeyError:
1248 context.set_details(
1249 'Alarm filter \'{}\' not found'.format(request.id))
1250 context.set_code(StatusCode.NOT_FOUND)
1251 return AlarmFilter()
ggowdru236bd952017-06-20 20:32:55 -07001252
1253 @twisted_async
1254 def GetImages(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -04001255 log.debug('grpc-request', request=request)
ggowdru236bd952017-06-20 20:32:55 -07001256
1257 if '/' in request.id:
1258 context.set_details(
1259 'Malformed device id \'{}\''.format(request.id))
1260 context.set_code(StatusCode.INVALID_ARGUMENT)
1261 return Images()
1262
1263 try:
1264 device = self.root.get('/devices/' + request.id)
1265 return device.images
1266
1267 except KeyError:
1268 context.set_details(
1269 'Device \'{}\' not found'.format(request.id))
1270 context.set_code(StatusCode.NOT_FOUND)
1271 return Images()
sathishg5ae86222017-06-28 15:16:29 +05301272
1273 @twisted_async
1274 def SelfTest(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -04001275 log.debug('grpc-request', request=request)
sathishg5ae86222017-06-28 15:16:29 +05301276
1277 if '/' in request.id:
1278 context.set_details(
1279 'Malformed device id \'{}\''.format(request.id))
1280 context.set_code(StatusCode.INVALID_ARGUMENT)
1281 return SelfTestResponse()
1282
1283 try:
1284 path = '/devices/{}'.format(request.id)
1285 device = self.root.get(path)
1286
1287 agent = self.core.get_device_agent(device.id)
1288 resp = agent.self_test(device)
1289 return resp.result
1290
1291 except KeyError:
1292 context.set_details(
1293 'Device \'{}\' not found'.format(request.id))
1294 context.set_code(StatusCode.NOT_FOUND)
1295 return SelfTestResponse()
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001296
1297 def _ofagent_session_termination(self):
1298 log.debug('start-ofagent-session-termination')
1299
1300 # Stop ofagent heartbeat
1301 if self.ofagent_heartbeat_lc is not None:
1302 self.ofagent_heartbeat_lc.stop()
1303
1304 # Reset flags and assignments
1305 self.ofagent_is_alive = False
1306 self.subscriber = None
1307 self.ofagent_heartbeat_count = 0
1308
1309 # Some local services will stop (packet-in/change-events)
1310 # need to re-register them
1311 registry('grpc_server').register(
1312 add_VolthaLocalServiceServicer_to_server, self)
1313
1314 log.debug('stop-ofagent-session-termination')
1315
1316 def _ofagent_session_heartbeat(self):
1317 log.debug('start-ofagent-heartbeat')
1318 if self.ofagent_heartbeat_count > self.ofagent_heartbeat_max_count:
1319 self._ofagent_session_termination()
1320 else:
1321 self.ofagent_heartbeat_count += 1
1322
1323 log.debug('stop-ofagent-heartbeat')
1324
1325 @twisted_async
1326 def Subscribe(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -04001327 log.debug('grpc-request', request=request)
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001328
1329 # Check if an ofagent subscriber is assigned
1330 if self.subscriber is None:
1331 log.debug('ofagent-subscriber-request')
1332
1333 try:
1334 # Assign the request as the active subscriber
1335 self.subscriber = OfAgentSubscriber(
1336 ofagent_id=request.ofagent_id,
1337 voltha_id=self.instance_id
1338 )
1339
1340 # Start the hearbeat
1341 self.ofagent_heartbeat_count = 0
1342 self.ofagent_heartbeat_lc = task.LoopingCall(self._ofagent_session_heartbeat)
1343 self.ofagent_heartbeat_lc.start(self.ofagent_heartbeat_delay)
1344
1345 log.debug('ofagent-subscriber-connected', subscriber=self.subscriber)
1346
1347 except _Rendezvous, e:
1348 log.error('ofagent-subscriber-failure', exception=repr(e), status=e.code())
1349
1350 except Exception as e:
1351 log.exception('ofagent-subscriber-unexpected-failure', exception=repr(e))
1352
1353 elif self.subscriber.ofagent_id == request.ofagent_id:
1354 log.debug('ofagent-subscriber-matches-assigned',
1355 current=self.subscriber)
1356 # reset counter
1357 self.ofagent_heartbeat_count = 0
1358
1359 else:
1360 log.debug('ofagent-subscriber-not-matching-assigned',
1361 current=self.subscriber)
1362
1363 return self.subscriber
Chip Boling69abce82018-06-18 09:56:23 -05001364
1365 @twisted_async
1366 def GetMibDeviceData(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -04001367 log.debug('grpc-request', request=request)
Chip Boling69abce82018-06-18 09:56:23 -05001368
1369 depth = int(dict(context.invocation_metadata()).get('get-depth', -1))
1370
1371 if '/' in request.id:
1372 context.set_details(
1373 'Malformed device id \'{}\''.format(request.id))
1374 context.set_code(StatusCode.INVALID_ARGUMENT)
1375 return MibDeviceData()
1376
1377 try:
1378 return self.root.get('/omci_mibs/' + request.id, depth=depth)
1379
1380 except KeyError:
1381 context.set_details(
1382 'OMCI MIB for Device \'{}\' not found'.format(request.id))
1383 context.set_code(StatusCode.NOT_FOUND)
1384 return MibDeviceData()
1385
jasonhuang5f3e63b2018-07-27 01:32:48 +08001386 @twisted_async
1387 def GetAlarmDeviceData(self, request, context):
1388 log.info('grpc-request', request=request)
1389
1390 depth = int(dict(context.invocation_metadata()).get('get-depth', -1))
1391
1392 if '/' in request.id:
1393 context.set_details(
1394 'Malformed device id \'{}\''.format(request.id))
1395 context.set_code(StatusCode.INVALID_ARGUMENT)
1396 return AlarmDeviceData()
1397
1398 try:
1399 return self.root.get('/omci_alarms/' + request.id, depth=depth)
1400
1401 except KeyError:
1402 context.set_details(
1403 'OMCI ALARM for Device \'{}\' not found'.format(request.id))
1404 context.set_code(StatusCode.NOT_FOUND)
Scott Bakerd3190952018-09-04 15:47:28 -07001405 return AlarmDeviceData()
1406
Koray Kokten8592a232018-08-27 07:41:14 +00001407 @twisted_async
1408 def UpdateLogicalDeviceMeterTable(self, request, context):
Koray Koktenefcdf522018-12-06 00:16:56 +03001409 log.info('meter-table-update-grpc-request', request=request)
Koray Kokten8592a232018-08-27 07:41:14 +00001410
Koray Koktenefcdf522018-12-06 00:16:56 +03001411 if '/' in request.id:
1412 context.set_details('Malformed logical device id \'{}\''.format(request.id))
1413 context.set_code(StatusCode.INVALID_ARGUMENT)
1414 return Empty()
1415
1416 try:
1417 agent = self.core.get_logical_device_agent(request.id)
1418 agent.update_meter_table(request.meter_mod)
1419 return Empty()
1420 except KeyError:
1421 context.set_details('Logical device \'{}\' not found'.format(request.id))
1422 context.set_code(StatusCode.NOT_FOUND)
1423 return Empty()
Koray Kokten8592a232018-08-27 07:41:14 +00001424
1425 @twisted_async
Gamze Abaka53cc0a22019-01-31 12:06:11 +00001426 def ListLogicalDeviceMeters(self, request, context):
1427 log.debug('grpc-request', request=request)
Koray Kokten8592a232018-08-27 07:41:14 +00001428
Gamze Abaka53cc0a22019-01-31 12:06:11 +00001429 if '/' in request.id:
1430 context.set_details(
1431 'Malformed logical device id \'{}\''.format(request.id))
1432 context.set_code(StatusCode.INVALID_ARGUMENT)
1433 return Meters()
1434
1435 try:
1436 meters = self.root.get(
1437 '/logical_devices/{}/meters'.format(request.id))
1438 log.debug("Found meters", meters=meters)
1439 return meters
1440 except KeyError:
1441 context.set_details(
1442 'Logical device \'{}\' not found'.format(request.id))
1443 context.set_code(StatusCode.NOT_FOUND)
1444 return Meters()
Koray Kokten8592a232018-08-27 07:41:14 +00001445
Scott Bakerd3190952018-09-04 15:47:28 -07001446 @twisted_async
1447 def SimulateAlarm(self, request, context):
1448 log.debug('grpc-request', request=request)
1449
1450 if '/' in request.id:
1451 context.set_details(
1452 'Malformed device id \'{}\''.format(request.id))
1453 context.set_code(StatusCode.INVALID_ARGUMENT)
1454 response = OperationResp(code=OperationResp.OPERATION_FAILURE)
1455 return response
1456
1457 try:
1458 path = '/devices/{}'.format(request.id)
1459 device = self.root.get(path)
1460 agent = self.core.get_device_agent(device.id)
1461 response = agent.simulate_alarm(device, request)
1462 return response
1463
1464 except KeyError:
1465 context.set_details(
1466 'Device \'{}\' not found'.format(request.id))
1467 context.set_code(StatusCode.NOT_FOUND)
1468 response = OperationResp(code=OperationResp.OPERATION_FAILURE)
1469 return response
1470 except Exception as e:
1471 log.exception(e.message)
1472 response = OperationResp(code=OperationResp.OPERATION_FAILURE)
Koray Kokten8592a232018-08-27 07:41:14 +00001473 return response