blob: 2a2df0503c7ccda202bf7a3f169b78579b4474fb [file] [log] [blame]
Zsolt Haraszti3eb27a52017-01-03 21:56:48 -08001# Copyright 2017 the original author or authors.
Zsolt Haraszti66862032016-11-28 14:28:39 -08002#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14#
Zsolt Haraszti3300f742017-01-09 01:14:20 -080015from Queue import Empty as QueueEmpty
Zsolt Haraszti66862032016-11-28 14:28:39 -080016from uuid import uuid4
17
18import structlog
Zsolt Haraszti3300f742017-01-09 01:14:20 -080019from google.protobuf.empty_pb2 import Empty
Zsolt Haraszti66862032016-11-28 14:28:39 -080020from grpc import StatusCode
Stephane Barbarie2940dac2017-08-18 14:15:17 -040021from grpc._channel import _Rendezvous
Zsolt Haraszti66862032016-11-28 14:28:39 -080022
23from common.utils.grpc_utils import twisted_async
Stephane Barbarie2940dac2017-08-18 14:15:17 -040024from twisted.internet import task
khenaidooa8588f22017-06-16 12:13:34 -040025from common.utils.id_generation import create_cluster_device_id
Zsolt Haraszti66862032016-11-28 14:28:39 -080026from voltha.core.config.config_root import ConfigRoot
Zsolt Haraszti217a12e2016-12-19 16:37:55 -080027from voltha.protos.openflow_13_pb2 import PacketIn, Flows, FlowGroups, \
28 ofp_port_status
Zsolt Haraszti66862032016-11-28 14:28:39 -080029from voltha.protos.voltha_pb2 import \
30 add_VolthaLocalServiceServicer_to_server, VolthaLocalServiceServicer, \
31 VolthaInstance, Adapters, LogicalDevices, LogicalDevice, Ports, \
Jonathan Hart8d21c322018-04-17 07:42:02 -070032 LogicalPort, LogicalPorts, Devices, Device, DeviceType, \
Stephane Barbarie4db8ca22017-04-24 10:30:20 -040033 DeviceTypes, DeviceGroups, DeviceGroup, AdminState, OperStatus, ChangeEvent, \
Stephane Barbarie2940dac2017-08-18 14:15:17 -040034 AlarmFilter, AlarmFilters, SelfTestResponse, OfAgentSubscriber
Lydia Fang01f2e852017-06-28 17:24:58 -070035from voltha.protos.device_pb2 import PmConfigs, Images, ImageDownload, ImageDownloads
36from voltha.protos.common_pb2 import OperationResp
Stephane Barbarie2940dac2017-08-18 14:15:17 -040037from voltha.protos.bbf_fiber_base_pb2 import AllMulticastDistributionSetData, AllMulticastGemportsConfigData
Zsolt Haraszti66862032016-11-28 14:28:39 -080038from voltha.registry import registry
Chip Boling69abce82018-06-18 09:56:23 -050039from voltha.protos.omci_mib_db_pb2 import MibDeviceData
jasonhuang5f3e63b2018-07-27 01:32:48 +080040from voltha.protos.omci_alarm_db_pb2 import AlarmDeviceData
Nikolay Titov89004ec2017-06-19 18:22:42 -040041from requests.api import request
Stephane Barbarie2940dac2017-08-18 14:15:17 -040042from common.utils.asleep import asleep
Zsolt Haraszti66862032016-11-28 14:28:39 -080043
44log = structlog.get_logger()
45
46
47class LocalHandler(VolthaLocalServiceServicer):
khenaidoo032d3302017-06-09 14:50:04 -040048 def __init__(self, core, instance_id, core_store_id, **init_kw):
Zsolt Haraszti66862032016-11-28 14:28:39 -080049 self.core = core
khenaidoo032d3302017-06-09 14:50:04 -040050 self.instance_id = instance_id
51 self.core_store_id = core_store_id
Zsolt Haraszti66862032016-11-28 14:28:39 -080052 self.init_kw = init_kw
53 self.root = None
khenaidoo032d3302017-06-09 14:50:04 -040054 self.started_with_existing_data = False
Zsolt Haraszti66862032016-11-28 14:28:39 -080055 self.stopped = False
56
Stephane Barbarie2940dac2017-08-18 14:15:17 -040057 self.restart_delay = 2
58 self.subscriber = None
59 self.ofagent_heartbeat_count = 0
60 self.ofagent_heartbeat_max_count = 3
61 self.ofagent_heartbeat_delay = 5
62 self.ofagent_heartbeat_lc = None
63 self.ofagent_is_alive = True
64
Ryan Van Gilder5a0ab622017-03-01 16:39:25 -080065 def start(self, config_backend=None):
Zsolt Haraszti66862032016-11-28 14:28:39 -080066 log.debug('starting')
Ryan Van Gilder5a0ab622017-03-01 16:39:25 -080067 if config_backend:
68 if 'root' in config_backend:
khenaidoo032d3302017-06-09 14:50:04 -040069 # This is going to block the entire reactor until loading is
70 # completed
71 log.info('loading-config-from-persisted-backend')
72 try:
73 self.root = ConfigRoot.load(VolthaInstance,
74 kv_store=config_backend)
75 self.started_with_existing_data = True
76 except Exception, e:
77 log.exception('Failure-loading-from-backend', e=e)
Ryan Van Gilder5a0ab622017-03-01 16:39:25 -080078 else:
khenaidoo032d3302017-06-09 14:50:04 -040079 log.info('initializing-a-new-config')
Khen Nursimulud068d812017-03-06 11:44:18 -050080 self.root = ConfigRoot(VolthaInstance(**self.init_kw),
81 kv_store=config_backend)
Ryan Van Gilder5a0ab622017-03-01 16:39:25 -080082 else:
83 self.root = ConfigRoot(VolthaInstance(**self.init_kw))
84
Nikolay Titov89004ec2017-06-19 18:22:42 -040085 self.core.xpon_handler.start(self.root)
86
Zsolt Haraszti66862032016-11-28 14:28:39 -080087 log.info('started')
88 return self
89
khenaidoocbe30832017-08-25 10:43:27 -040090 def register_grpc_service(self):
91 log.debug('registering')
92 registry('grpc_server').register(
93 add_VolthaLocalServiceServicer_to_server, self)
94 log.info('registered')
95
96
Zsolt Haraszti66862032016-11-28 14:28:39 -080097 def stop(self):
98 log.debug('stopping')
99 self.stopped = True
Stephane Barbarie2940dac2017-08-18 14:15:17 -0400100
101 if self.ofagent_heartbeat_lc is not None:
102 self.ofagent_heartbeat_lc.stop()
103
104 self._ofagent_session_termination()
105
Zsolt Haraszti66862032016-11-28 14:28:39 -0800106 log.info('stopped')
107
108 def get_proxy(self, path, exclusive=False):
109 return self.root.get_proxy(path, exclusive)
110
khenaidoo032d3302017-06-09 14:50:04 -0400111 def has_started_with_existing_data(self):
112 return self.started_with_existing_data
113
Zsolt Haraszti66862032016-11-28 14:28:39 -0800114 # gRPC service method implementations. BE CAREFUL; THESE ARE CALLED ON
115 # the gRPC threadpool threads.
116
117 @twisted_async
118 def GetVolthaInstance(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400119 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800120 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
121 res = self.root.get('/', depth=depth)
122 return res
123
124 @twisted_async
125 def GetHealth(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400126 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800127 return self.root.get('/health')
128
129 @twisted_async
130 def ListAdapters(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400131 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800132 items = self.root.get('/adapters')
khenaidooc4832162017-09-20 11:55:04 -0400133 sorted_items = sorted(items, key=lambda i: i.id)
134 return Adapters(items=sorted_items)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800135
136 @twisted_async
137 def ListLogicalDevices(self, request, context):
Matteo Scandolo83dedc12018-09-16 15:11:44 +0000138 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800139 items = self.root.get('/logical_devices')
140 return LogicalDevices(items=items)
141
142 @twisted_async
143 def GetLogicalDevice(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400144 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800145
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800146 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
147
Zsolt Haraszti66862032016-11-28 14:28:39 -0800148 if '/' in request.id:
149 context.set_details(
150 'Malformed logical device id \'{}\''.format(request.id))
151 context.set_code(StatusCode.INVALID_ARGUMENT)
152 return LogicalDevice()
153
154 try:
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800155 return self.root.get('/logical_devices/' + request.id, depth=depth)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800156 except KeyError:
157 context.set_details(
158 'Logical device \'{}\' not found'.format(request.id))
159 context.set_code(StatusCode.NOT_FOUND)
160 return LogicalDevice()
161
162 @twisted_async
163 def ListLogicalDevicePorts(self, request, context):
Matteo Scandolo83dedc12018-09-16 15:11:44 +0000164 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800165
166 if '/' in request.id:
167 context.set_details(
168 'Malformed logical device id \'{}\''.format(request.id))
169 context.set_code(StatusCode.INVALID_ARGUMENT)
170 return LogicalPorts()
171
172 try:
Khen Nursimulud068d812017-03-06 11:44:18 -0500173 items = self.root.get(
174 '/logical_devices/{}/ports'.format(request.id))
Zsolt Haraszti66862032016-11-28 14:28:39 -0800175 return LogicalPorts(items=items)
176 except KeyError:
177 context.set_details(
178 'Logical device \'{}\' not found'.format(request.id))
179 context.set_code(StatusCode.NOT_FOUND)
180 return LogicalPorts()
181
182 @twisted_async
Jonathan Hart8d21c322018-04-17 07:42:02 -0700183 def GetLogicalDevicePort(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400184 log.debug('grpc-request', requst=request)
Jonathan Hart8d21c322018-04-17 07:42:02 -0700185
186 if '/' in request.id:
187 context.set_details(
188 'Malformed logical device id \'{}\''.format(request.id))
189 context.set_code(StatusCode.INVALID_ARGUMENT)
190 return LogicalPort()
191
192 try:
193 return self.root.get(
194 '/logical_devices/{}/ports/{}'.format(request.id, request.port_id))
195 except KeyError:
196 context.set_details(
197 'Logical port \'{}\' not found on device \'{}\''.format(request.port_id, request.id))
198 context.set_code(StatusCode.NOT_FOUND)
199 return LogicalPort()
200
201 @twisted_async
Zsolt Haraszti66862032016-11-28 14:28:39 -0800202 def ListLogicalDeviceFlows(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400203 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800204
205 if '/' in request.id:
206 context.set_details(
207 'Malformed logical device id \'{}\''.format(request.id))
208 context.set_code(StatusCode.INVALID_ARGUMENT)
209 return Flows()
210
211 try:
Khen Nursimulud068d812017-03-06 11:44:18 -0500212 flows = self.root.get(
213 '/logical_devices/{}/flows'.format(request.id))
Zsolt Haraszti66862032016-11-28 14:28:39 -0800214 return flows
215 except KeyError:
216 context.set_details(
217 'Logical device \'{}\' not found'.format(request.id))
218 context.set_code(StatusCode.NOT_FOUND)
219 return Flows()
220
Zsolt Haraszti66862032016-11-28 14:28:39 -0800221 @twisted_async
Jonathan Hart8d21c322018-04-17 07:42:02 -0700222 def EnableLogicalDevicePort(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400223 log.debug('grpc-request', request=request)
Jonathan Hart8d21c322018-04-17 07:42:02 -0700224
225 if '/' in request.id:
226 context.set_details(
227 'Malformed logical device id \'{}\''.format(request.id))
228 context.set_code(StatusCode.INVALID_ARGUMENT)
229 return Empty()
230
231 try:
232 agent = self.core.get_logical_device_agent(request.id)
233 agent.port_enable(request.port_id)
234 return Empty()
235 except KeyError:
236 context.set_details(
237 'Logical device \'{}\' not found'.format(request.id))
238 context.set_code(StatusCode.NOT_FOUND)
239 return Empty()
240
241 @twisted_async
242 def DisableLogicalDevicePort(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400243 log.debug('grpc-request', request=request)
Jonathan Hart8d21c322018-04-17 07:42:02 -0700244
245 if '/' in request.id:
246 context.set_details(
247 'Malformed logical device id \'{}\''.format(request.id))
248 context.set_code(StatusCode.INVALID_ARGUMENT)
249 return Empty()
250
251 try:
252 agent = self.core.get_logical_device_agent(request.id)
253 agent.port_disable(request.port_id)
254 return Empty()
255 except KeyError:
256 context.set_details(
257 'Logical device \'{}\' not found'.format(request.id))
258 context.set_code(StatusCode.NOT_FOUND)
259 return Empty()
260
261 @twisted_async
Zsolt Haraszti66862032016-11-28 14:28:39 -0800262 def UpdateLogicalDeviceFlowTable(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400263 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800264
265 if '/' in request.id:
266 context.set_details(
267 'Malformed logical device id \'{}\''.format(request.id))
268 context.set_code(StatusCode.INVALID_ARGUMENT)
269 return Empty()
270
271 try:
272 agent = self.core.get_logical_device_agent(request.id)
273 agent.update_flow_table(request.flow_mod)
274 return Empty()
275 except KeyError:
276 context.set_details(
277 'Logical device \'{}\' not found'.format(request.id))
278 context.set_code(StatusCode.NOT_FOUND)
279 return Empty()
280
281 @twisted_async
282 def ListLogicalDeviceFlowGroups(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400283 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800284
285 if '/' in request.id:
286 context.set_details(
287 'Malformed logical device id \'{}\''.format(request.id))
288 context.set_code(StatusCode.INVALID_ARGUMENT)
289 return FlowGroups()
290
291 try:
292 groups = self.root.get(
293 '/logical_devices/{}/flow_groups'.format(request.id))
294 return groups
295 except KeyError:
296 context.set_details(
297 'Logical device \'{}\' not found'.format(request.id))
298 context.set_code(StatusCode.NOT_FOUND)
299 return FlowGroups()
300
301 @twisted_async
302 def UpdateLogicalDeviceFlowGroupTable(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400303 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800304
305 if '/' in request.id:
306 context.set_details(
307 'Malformed logical device id \'{}\''.format(request.id))
308 context.set_code(StatusCode.INVALID_ARGUMENT)
309 return Empty()
310
311 try:
312 agent = self.core.get_logical_device_agent(request.id)
313 agent.update_group_table(request.group_mod)
314 return Empty()
315 except KeyError:
316 context.set_details(
317 'Logical device \'{}\' not found'.format(request.id))
318 context.set_code(StatusCode.NOT_FOUND)
319 return Empty()
320
321 @twisted_async
322 def ListDevices(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400323 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800324 items = self.root.get('/devices')
325 return Devices(items=items)
326
327 @twisted_async
328 def GetDevice(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400329 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800330
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800331 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
332
Zsolt Haraszti66862032016-11-28 14:28:39 -0800333 if '/' in request.id:
334 context.set_details(
335 'Malformed device id \'{}\''.format(request.id))
336 context.set_code(StatusCode.INVALID_ARGUMENT)
337 return Device()
338
339 try:
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800340 return self.root.get('/devices/' + request.id, depth=depth)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800341 except KeyError:
342 context.set_details(
343 'Device \'{}\' not found'.format(request.id))
344 context.set_code(StatusCode.NOT_FOUND)
345 return Device()
346
347 @twisted_async
348 def CreateDevice(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400349 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800350
351 known_device_types = dict(
352 (dt.id, dt) for dt in self.root.get('/device_types'))
Nikolay Titovff35fb32017-09-24 13:33:29 -0400353 known_devices = self.root.get('/devices')
Zsolt Haraszti66862032016-11-28 14:28:39 -0800354
355 try:
356 assert isinstance(request, Device)
357 device = request
358 assert device.id == '', 'Device to be created cannot have id yet'
359 assert device.type in known_device_types, \
360 'Unknown device type \'{}\''.format(device.type)
361 assert device.admin_state in (AdminState.UNKNOWN,
362 AdminState.PREPROVISIONED), \
363 'Newly created device cannot be ' \
364 'in admin state \'{}\''.format(device.admin_state)
Nikolay Titovff35fb32017-09-24 13:33:29 -0400365 assert device.WhichOneof("address") is not None, \
366 'Device must have one contact address e.g. MAC, IPv4, IPv6, H&P'
367 error_message = 'Device with {} address \'{}\' already exists'
368 for _device in known_devices:
369 if _device.HasField(device.WhichOneof("address")):
370 if device.HasField("mac_address"):
371 assert device.mac_address != _device.mac_address, \
372 error_message.format('MAC', device.mac_address)
373 elif device.HasField("ipv4_address"):
374 assert device.ipv4_address != _device.ipv4_address, \
375 error_message.format('IPv4', device.ipv4_address)
376 elif device.HasField("ipv6_address"):
377 assert device.ipv6_address != _device.ipv6_address, \
378 error_message.format('IPv6', device.ipv6_address)
379 elif device.HasField("host_and_port"):
380 assert device.host_and_port != _device.host_and_port, \
381 error_message.format('Host and Port',
382 device.host_and_port)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800383 except AssertionError, e:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400384 context.set_details(e.message)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800385 context.set_code(StatusCode.INVALID_ARGUMENT)
386 return Device()
387
388 # fill additional data
khenaidooa8588f22017-06-16 12:13:34 -0400389 device.id = create_cluster_device_id(self.core_store_id)
390 log.debug('device-id-created', device_id=device.id)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800391 device_type = known_device_types[device.type]
392 device.adapter = device_type.adapter
393 if device.admin_state != AdminState.PREPROVISIONED:
394 device.admin_state = AdminState.PREPROVISIONED
395 device.oper_status = OperStatus.UNKNOWN
Niren R Chidrawara5753632017-08-31 03:18:03 -0400396 device.vendor_id = device_type.vendor_id
Zsolt Haraszti66862032016-11-28 14:28:39 -0800397
398 # add device to tree
399 self.root.add('/devices', device)
400
401 return request
402
403 @twisted_async
Khen Nursimulud068d812017-03-06 11:44:18 -0500404 def EnableDevice(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400405 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800406
407 if '/' in request.id:
408 context.set_details(
409 'Malformed device id \'{}\''.format(request.id))
410 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400411 return Empty()
Zsolt Haraszti66862032016-11-28 14:28:39 -0800412
413 try:
414 path = '/devices/{}'.format(request.id)
415 device = self.root.get(path)
Khen Nursimulud068d812017-03-06 11:44:18 -0500416 assert device.admin_state in (AdminState.PREPROVISIONED,
417 AdminState.DISABLED), \
418 'Device to enable cannot be ' \
419 'in admin state \'{}\''.format(device.admin_state)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800420 device.admin_state = AdminState.ENABLED
421 self.root.update(path, device, strict=True)
422
Khen Nursimulud068d812017-03-06 11:44:18 -0500423 except AssertionError, e:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400424 context.set_details(e.message)
Khen Nursimulud068d812017-03-06 11:44:18 -0500425 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimulud068d812017-03-06 11:44:18 -0500426
427 except KeyError:
428 context.set_details(
429 'Device \'{}\' not found'.format(request.id))
430 context.set_code(StatusCode.NOT_FOUND)
431
432 return Empty()
433
434 @twisted_async
435 def DisableDevice(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400436 log.debug('grpc-request', request=request)
Khen Nursimulud068d812017-03-06 11:44:18 -0500437
438 if '/' in request.id:
439 context.set_details(
440 'Malformed device id \'{}\''.format(request.id))
441 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400442 return Empty()
Khen Nursimulud068d812017-03-06 11:44:18 -0500443 try:
444 path = '/devices/{}'.format(request.id)
445 device = self.root.get(path)
446 assert device.admin_state == AdminState.ENABLED, \
447 'Device to disable cannot be ' \
448 'in admin state \'{}\''.format(device.admin_state)
449 device.admin_state = AdminState.DISABLED
450 self.root.update(path, device, strict=True)
451
452 except AssertionError, e:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400453 context.set_details(e.message)
Khen Nursimulud068d812017-03-06 11:44:18 -0500454 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimulud068d812017-03-06 11:44:18 -0500455
456 except KeyError:
457 context.set_details(
458 'Device \'{}\' not found'.format(request.id))
459 context.set_code(StatusCode.NOT_FOUND)
460
khenaidoo032d3302017-06-09 14:50:04 -0400461 except Exception, e:
462 log.exception('disable-exception', e=e)
463
Khen Nursimulud068d812017-03-06 11:44:18 -0500464 return Empty()
465
466 @twisted_async
467 def RebootDevice(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400468 log.debug('grpc-request', request=request)
Khen Nursimulud068d812017-03-06 11:44:18 -0500469
470 if '/' in request.id:
471 context.set_details(
472 'Malformed device id \'{}\''.format(request.id))
473 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400474 return Empty()
Khen Nursimulud068d812017-03-06 11:44:18 -0500475
476 try:
477 path = '/devices/{}'.format(request.id)
478 device = self.root.get(path)
Lydia Fang01f2e852017-06-28 17:24:58 -0700479 assert device.admin_state != AdminState.DOWNLOADING_IMAGE, \
480 'Device to reboot cannot be ' \
481 'in admin state \'{}\''.format(device.admin_state)
Khen Nursimulud068d812017-03-06 11:44:18 -0500482 agent = self.core.get_device_agent(device.id)
483 agent.reboot_device(device)
484
Khen Nursimulud068d812017-03-06 11:44:18 -0500485 except KeyError:
486 context.set_details(
487 'Device \'{}\' not found'.format(request.id))
488 context.set_code(StatusCode.NOT_FOUND)
489
490 return Empty()
491
492 @twisted_async
Lydia Fang01f2e852017-06-28 17:24:58 -0700493 def DownloadImage(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400494 log.debug('grpc-request', request=request)
Lydia Fang01f2e852017-06-28 17:24:58 -0700495
496 if '/' in request.id:
497 context.set_details(
498 'Malformed device id \'{}\''.format(request.id))
499 context.set_code(StatusCode.INVALID_ARGUMENT)
500 return OperationResp(code=OperationResp.OPERATION_FAILURE)
501
502 try:
503 path = '/devices/{}'.format(request.id)
504 device = self.root.get(path)
505 assert isinstance(request, ImageDownload)
506 self.root.add('/devices/{}/image_downloads'.\
507 format(request.id), request)
508 assert device.admin_state == AdminState.ENABLED, \
509 'Device to DOWNLOADING_IMAGE cannot be ' \
510 'in admin state \'{}\''.format(device.admin_state)
511 device.admin_state = AdminState.DOWNLOADING_IMAGE
512 self.root.update(path, device, strict=True)
513 agent = self.core.get_device_agent(device.id)
514 agent.register_image_download(request)
515 return OperationResp(code=OperationResp.OPERATION_SUCCESS)
516
517 except AssertionError as e:
518 context.set_details(e.message)
519 context.set_code(StatusCode.INVALID_ARGUMENT)
520 return OperationResp(code=OperationResp.OPERATION_UNSUPPORTED)
521
522 except KeyError:
523 context.set_details(
524 'Device \'{}\' not found'.format(request.id))
525 context.set_code(StatusCode.NOT_FOUND)
526 return OperationResp(code=OperationResp.OPERATION_FAILURE)
527
528 except Exception as e:
529 log.exception(e.message)
530 context.set_code(StatusCode.NOT_FOUND)
531 return OperationResp(code=OperationResp.OPERATION_FAILURE)
532
533 @twisted_async
534 def GetImageDownloadStatus(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400535 log.debug('grpc-request', request=request)
Lydia Fang01f2e852017-06-28 17:24:58 -0700536
537 if '/' in request.id:
538 context.set_details(
539 'Malformed device id \'{}\''.format(request.id))
540 context.set_code(StatusCode.INVALID_ARGUMENT)
541 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
542 return response
543
544 try:
545 path = '/devices/{}'.format(request.id)
546 device = self.root.get(path)
547 agent = self.core.get_device_agent(device.id)
548 img_dnld = self.root.get('/devices/{}/image_downloads/{}'.\
549 format(request.id, request.name))
550 agent.get_image_download_status(img_dnld)
551 try:
552 response = self.root.get('/devices/{}/image_downloads/{}'.\
553 format(request.id, request.name))
554 except Exception as e:
555 log.exception(e.message)
556 return response
557
558 except KeyError:
559 context.set_details(
560 'Device \'{}\' not found'.format(request.id))
561 context.set_code(StatusCode.NOT_FOUND)
562 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
563 return response
564 except Exception as e:
565 log.exception(e.message)
566 response = ImageDownload(state=ImageDownload.DOWNLOAD_FAILED)
567 return response
568
569 @twisted_async
570 def GetImageDownload(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400571 log.debug('grpc-request', request=request)
Lydia Fang01f2e852017-06-28 17:24:58 -0700572
573 if '/' in request.id:
574 context.set_details(
575 'Malformed device id \'{}\''.format(request.id))
576 context.set_code(StatusCode.INVALID_ARGUMENT)
577 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
578 return response
579
580 try:
581 response = self.root.get('/devices/{}/image_downloads/{}'.\
582 format(request.id, request.name))
583 return response
584
585 except KeyError:
586 context.set_details(
587 'Device \'{}\' not found'.format(request.id))
588 context.set_code(StatusCode.NOT_FOUND)
589 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
590 return response
591
592 @twisted_async
593 def ListImageDownloads(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400594 log.debug('grpc-request', request=request)
Lydia Fang01f2e852017-06-28 17:24:58 -0700595
596 if '/' in request.id:
597 context.set_details(
598 'Malformed device id \'{}\''.format(request.id))
599 context.set_code(StatusCode.INVALID_ARGUMENT)
600 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
601 return response
602
603 try:
604 response = self.root.get('/devices/{}/image_downloads'.\
605 format(request.id))
606 return ImageDownloads(items=response)
607
608 except KeyError:
609 context.set_details(
610 'Device \'{}\' not found'.format(request.id))
611 context.set_code(StatusCode.NOT_FOUND)
612 response = ImageDownload(state=ImageDownload.DOWNLOAD_UNKNOWN)
613 return response
614
615 @twisted_async
616 def CancelImageDownload(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400617 log.debug('grpc-request', request=request)
Lydia Fang01f2e852017-06-28 17:24:58 -0700618
619 if '/' in request.id:
620 context.set_details(
621 'Malformed device id \'{}\''.format(request.id))
622 context.set_code(StatusCode.INVALID_ARGUMENT)
623 return OperationResp(code=OperationResp.OPERATION_FAILURE)
624
625 try:
626 assert isinstance(request, ImageDownload)
627 path = '/devices/{}'.format(request.id)
628 device = self.root.get(path)
629 assert device.admin_state == AdminState.DOWNLOADING_IMAGE, \
630 'Device to cancel DOWNLOADING_IMAGE cannot be ' \
631 'in admin state \'{}\''.format(device.admin_state)
632 agent = self.core.get_device_agent(device.id)
633 agent.cancel_image_download(request)
634 return OperationResp(code=OperationResp.OPERATION_SUCCESS)
635
636 except KeyError:
637 context.set_details(
638 'Device \'{}\' not found'.format(request.id))
639 context.set_code(StatusCode.NOT_FOUND)
640 return OperationResp(code=OperationResp.OPERATION_FAILURE)
641
642 @twisted_async
643 def ActivateImageUpdate(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400644 log.debug('grpc-request', request=request)
Lydia Fang01f2e852017-06-28 17:24:58 -0700645
646 if '/' in request.id:
647 context.set_details(
648 'Malformed device id \'{}\''.format(request.id))
649 context.set_code(StatusCode.INVALID_ARGUMENT)
650 return OperationResp(code=OperationResp.OPERATION_FAILURE)
651
652 try:
653 assert isinstance(request, ImageDownload)
654 path = '/devices/{}'.format(request.id)
655 device = self.root.get(path)
656 assert device.admin_state == AdminState.ENABLED, \
657 'Device to activate image cannot be ' \
658 'in admin state \'{}\''.format(device.admin_state)
659 agent = self.core.get_device_agent(device.id)
660 agent.activate_image_update(request)
661 return OperationResp(code=OperationResp.OPERATION_SUCCESS)
662
663 except KeyError:
664 context.set_details(
665 'Device \'{}\' not found'.format(request.id))
666 context.set_code(StatusCode.NOT_FOUND)
667 return OperationResp(code=OperationResp.OPERATION_FAILURE)
668
669 @twisted_async
670 def RevertImageUpdate(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400671 log.debug('grpc-request', request=request)
Lydia Fang01f2e852017-06-28 17:24:58 -0700672
673 if '/' in request.id:
674 context.set_details(
675 'Malformed device id \'{}\''.format(request.id))
676 context.set_code(StatusCode.INVALID_ARGUMENT)
677 return OperationResp(code=OperationResp.OPERATION_FAILURE)
678
679 try:
680 assert isinstance(request, ImageDownload)
681 path = '/devices/{}'.format(request.id)
682 device = self.root.get(path)
683 assert device.admin_state == AdminState.ENABLED, \
684 'Device to revert image cannot be ' \
685 'in admin state \'{}\''.format(device.admin_state)
686 agent = self.core.get_device_agent(device.id)
687 agent.revert_image_update(request)
688 return OperationResp(code=OperationResp.OPERATION_SUCCESS)
689
690 except KeyError:
691 context.set_details(
692 'Device \'{}\' not found'.format(request.id))
693 context.set_code(StatusCode.NOT_FOUND)
694 return OperationResp(code=OperationResp.OPERATION_FAILURE)
695
696 @twisted_async
Khen Nursimulud068d812017-03-06 11:44:18 -0500697 def DeleteDevice(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400698 log.debug('grpc-request', request=request)
Khen Nursimulud068d812017-03-06 11:44:18 -0500699
700 if '/' in request.id:
701 context.set_details(
702 'Malformed device id \'{}\''.format(request.id))
703 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400704 return Empty()
Khen Nursimulud068d812017-03-06 11:44:18 -0500705
706 try:
707 path = '/devices/{}'.format(request.id)
708 device = self.root.get(path)
Venkata Telu41e72862018-06-11 11:54:43 -0500709 assert device.admin_state == AdminState.DISABLED or device.admin_state == AdminState.PREPROVISIONED, \
Khen Nursimulud068d812017-03-06 11:44:18 -0500710 'Device to delete cannot be ' \
711 'in admin state \'{}\''.format(device.admin_state)
712
713 self.root.remove(path)
714
715 except AssertionError, e:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400716 context.set_details(e.message)
Khen Nursimulud068d812017-03-06 11:44:18 -0500717 context.set_code(StatusCode.INVALID_ARGUMENT)
Khen Nursimulud068d812017-03-06 11:44:18 -0500718
Zsolt Haraszti66862032016-11-28 14:28:39 -0800719 except KeyError:
720 context.set_details(
721 'Device \'{}\' not found'.format(request.id))
722 context.set_code(StatusCode.NOT_FOUND)
723
724 return Empty()
725
726 @twisted_async
727 def ListDevicePorts(self, request, context):
Matteo Scandolo83dedc12018-09-16 15:11:44 +0000728 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800729
730 if '/' in request.id:
731 context.set_details(
732 'Malformed device id \'{}\''.format(request.id))
733 context.set_code(StatusCode.INVALID_ARGUMENT)
734 return Ports()
735
736 try:
737 items = self.root.get('/devices/{}/ports'.format(request.id))
738 return Ports(items=items)
739 except KeyError:
740 context.set_details(
741 'Device \'{}\' not found'.format(request.id))
742 context.set_code(StatusCode.NOT_FOUND)
743 return Ports()
744
Sergio Slobodriana2eb52b2017-03-07 12:24:46 -0500745 @twisted_async
746 def ListDevicePmConfigs(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400747 log.debug('grpc-request', request=request)
Sergio Slobodriana2eb52b2017-03-07 12:24:46 -0500748
Sergio Slobodrian71960022017-03-09 10:20:57 -0500749 if '/' in request.id:
750 context.set_details(
751 'Malformed device id \'{}\''.format(request.id))
752 context.set_code(StatusCode.INVALID_ARGUMENT)
753 return PmConfigs()
754
755 try:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400756 pm_configs = self.root.get(
757 '/devices/{}/pm_configs'.format(request.id))
Sergio Slobodrian2db4c102017-03-09 22:29:23 -0500758 pm_configs.id = request.id
khenaidoo5431e4c2017-08-17 15:05:40 -0400759 log.debug('device-for-pms', pm_configs=pm_configs)
Sergio Slobodrian2db4c102017-03-09 22:29:23 -0500760 return pm_configs
Sergio Slobodrian71960022017-03-09 10:20:57 -0500761 except KeyError:
762 context.set_details(
763 'Device \'{}\' not found'.format(request.id))
764 context.set_code(StatusCode.NOT_FOUND)
765 return PmConfigs()
766
Sergio Slobodriana2eb52b2017-03-07 12:24:46 -0500767 @twisted_async
768 def UpdateDevicePmConfigs(self, request, context):
khenaidoo5431e4c2017-08-17 15:05:40 -0400769 log.debug('grpc-request', request=request)
Sergio Slobodrian2db4c102017-03-09 22:29:23 -0500770
771 if '/' in request.id:
772 context.set_details(
773 'Malformed logical device id \'{}\''.format(request.id))
774 context.set_code(StatusCode.INVALID_ARGUMENT)
775 return Empty()
776
777 try:
778 device = self.root.get('/devices/{}'.format(request.id))
779 agent = self.core.get_device_agent(request.id)
780 agent.update_device_pm_config(request)
781 return Empty()
782 except KeyError:
783 context.set_details(
784 'Device \'{}\' not found'.format(request.id))
785 context.set_code(StatusCode.NOT_FOUND)
786 return Empty()
Sergio Slobodriana2eb52b2017-03-07 12:24:46 -0500787
Zsolt Haraszti66862032016-11-28 14:28:39 -0800788 @twisted_async
789 def ListDeviceFlows(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400790 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800791
792 if '/' in request.id:
793 context.set_details(
794 'Malformed device id \'{}\''.format(request.id))
795 context.set_code(StatusCode.INVALID_ARGUMENT)
796 return Flows()
797
798 try:
799 flows = self.root.get('/devices/{}/flows'.format(request.id))
800 return flows
801 except KeyError:
802 context.set_details(
803 'Device \'{}\' not found'.format(request.id))
804 context.set_code(StatusCode.NOT_FOUND)
805 return Flows()
806
Zsolt Haraszti66862032016-11-28 14:28:39 -0800807 @twisted_async
808 def ListDeviceFlowGroups(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 FlowGroups()
816
817 try:
Khen Nursimulud068d812017-03-06 11:44:18 -0500818 groups = self.root.get(
819 '/devices/{}/flow_groups'.format(request.id))
Zsolt Haraszti66862032016-11-28 14:28:39 -0800820 return groups
821 except KeyError:
822 context.set_details(
823 'Device \'{}\' not found'.format(request.id))
824 context.set_code(StatusCode.NOT_FOUND)
825 return FlowGroups()
826
827 @twisted_async
828 def ListDeviceTypes(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400829 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800830 items = self.root.get('/device_types')
khenaidooc4832162017-09-20 11:55:04 -0400831 sorted_items = sorted(items, key=lambda i: i.id)
832 return DeviceTypes(items=sorted_items)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800833
834 @twisted_async
835 def GetDeviceType(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400836 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800837
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800838 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
839
Zsolt Haraszti66862032016-11-28 14:28:39 -0800840 if '/' in request.id:
841 context.set_details(
842 'Malformed device type id \'{}\''.format(request.id))
843 context.set_code(StatusCode.INVALID_ARGUMENT)
844 return DeviceType()
845
846 try:
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800847 return self.root.get('/device_types/' + request.id, depth=depth)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800848 except KeyError:
849 context.set_details(
850 'Device type \'{}\' not found'.format(request.id))
851 context.set_code(StatusCode.NOT_FOUND)
852 return DeviceType()
853
854 @twisted_async
855 def ListDeviceGroups(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400856 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800857 # TODO is this mapped to tree or taken from coordinator?
858 items = self.root.get('/device_groups')
859 return DeviceGroups(items=items)
860
861 @twisted_async
862 def GetDeviceGroup(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400863 log.debug('grpc-request', request=request)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800864
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800865 depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
866
Zsolt Haraszti66862032016-11-28 14:28:39 -0800867 if '/' in request.id:
868 context.set_details(
869 'Malformed device group id \'{}\''.format(request.id))
870 context.set_code(StatusCode.INVALID_ARGUMENT)
871 return DeviceGroup()
872
873 # TODO is this mapped to tree or taken from coordinator?
874 try:
Zsolt Harasztif7722f92016-12-13 17:54:30 -0800875 return self.root.get('/device_groups/' + request.id, depth=depth)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800876 except KeyError:
877 context.set_details(
878 'Device group \'{}\' not found'.format(request.id))
879 context.set_code(StatusCode.NOT_FOUND)
880 return DeviceGroup()
881
Nikolay Titov89004ec2017-06-19 18:22:42 -0400882 # bbf_fiber rpcs start
883 @twisted_async
884 def GetAllChannelgroupConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400885 return self.core.xpon_handler.get_all_channel_group_config(
886 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400887
888 @twisted_async
889 def CreateChannelgroup(self, request, context):
890 return self.core.xpon_handler.create_channel_group(request, context)
891
892 @twisted_async
893 def UpdateChannelgroup(self, request, context):
894 return self.core.xpon_handler.update_channel_group(request, context)
895
896 @twisted_async
897 def DeleteChannelgroup(self, request, context):
898 return self.core.xpon_handler.delete_channel_group(request, context)
899
900 @twisted_async
901 def GetAllChannelpartitionConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400902 return self.core.xpon_handler.get_all_channel_partition_config(
903 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400904
905 @twisted_async
906 def CreateChannelpartition(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400907 return self.core.xpon_handler.create_channel_partition(
908 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400909
910 @twisted_async
911 def UpdateChannelpartition(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400912 return self.core.xpon_handler.update_channel_partition(
913 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400914
915 @twisted_async
916 def DeleteChannelpartition(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400917 return self.core.xpon_handler.delete_channel_partition(
918 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400919
920 @twisted_async
921 def GetAllChannelpairConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400922 return self.core.xpon_handler.get_all_channel_pair_config(
923 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400924
925 @twisted_async
926 def CreateChannelpair(self, request, context):
927 return self.core.xpon_handler.create_channel_pair(request, context)
928
929 @twisted_async
930 def UpdateChannelpair(self, request, context):
931 return self.core.xpon_handler.update_channel_pair(request, context)
932
933 @twisted_async
934 def DeleteChannelpair(self, request, context):
935 return self.core.xpon_handler.delete_channel_pair(request, context)
936
937 @twisted_async
938 def GetAllChannelterminationConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400939 return self.core.xpon_handler.get_all_channel_termination_config(
940 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400941
942 @twisted_async
943 def CreateChanneltermination(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400944 return self.core.xpon_handler.create_channel_termination(
945 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400946
947 @twisted_async
948 def UpdateChanneltermination(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400949 return self.core.xpon_handler.update_channel_termination(
950 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400951
952 @twisted_async
953 def DeleteChanneltermination(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400954 return self.core.xpon_handler.delete_channel_termination(
955 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400956
957 @twisted_async
958 def GetAllOntaniConfig(self, request, context):
959 return self.core.xpon_handler.get_all_ont_ani_config(request, context)
960
961 @twisted_async
962 def CreateOntani(self, request, context):
963 return self.core.xpon_handler.create_ont_ani(request, context)
964
965 @twisted_async
966 def UpdateOntani(self, request, context):
967 return self.core.xpon_handler.update_ont_ani(request, context)
968
969 @twisted_async
970 def DeleteOntani(self, request, context):
971 return self.core.xpon_handler.delete_ont_ani(request, context)
972
973 @twisted_async
974 def GetAllVOntaniConfig(self, request, context):
Nikolay Titov3b31db92017-08-02 18:11:33 -0400975 return self.core.xpon_handler.get_all_v_ont_ani_config(
976 request, context)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400977
978 @twisted_async
979 def CreateVOntani(self, request, context):
980 return self.core.xpon_handler.create_v_ont_ani(request, context)
981
982 @twisted_async
983 def UpdateVOntani(self, request, context):
984 return self.core.xpon_handler.update_v_ont_ani(request, context)
985
986 @twisted_async
987 def DeleteVOntani(self, request, context):
988 return self.core.xpon_handler.delete_v_ont_ani(request, context)
989
990 @twisted_async
991 def GetAllVEnetConfig(self, request, context):
992 return self.core.xpon_handler.get_all_v_enet_config(request, context)
993
994 @twisted_async
995 def CreateVEnet(self, request, context):
996 return self.core.xpon_handler.create_v_enet(request, context)
997
998 @twisted_async
999 def UpdateVEnet(self, request, context):
1000 return self.core.xpon_handler.update_v_enet(request, context)
1001
1002 @twisted_async
1003 def DeleteVEnet(self, request, context):
1004 return self.core.xpon_handler.delete_v_enet(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001005
1006 @twisted_async
1007 def GetAllTrafficDescriptorProfileData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001008 return self.core.xpon_handler.get_all_traffic_descriptor_profile_data(
1009 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001010
1011 @twisted_async
1012 def CreateTrafficDescriptorProfileData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001013 return self.core.xpon_handler.create_traffic_descriptor_profile(
1014 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001015
1016 @twisted_async
1017 def UpdateTrafficDescriptorProfileData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001018 return self.core.xpon_handler.update_traffic_descriptor_profile(
1019 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001020
1021 @twisted_async
1022 def DeleteTrafficDescriptorProfileData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001023 return self.core.xpon_handler.delete_traffic_descriptor_profile(
1024 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001025
1026 @twisted_async
1027 def GetAllTcontsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001028 return self.core.xpon_handler.get_all_tconts_config_data(
1029 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001030
1031 @twisted_async
1032 def CreateTcontsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001033 return self.core.xpon_handler.create_tcont(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001034
1035 @twisted_async
1036 def UpdateTcontsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001037 return self.core.xpon_handler.update_tcont(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001038
1039 @twisted_async
1040 def DeleteTcontsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001041 return self.core.xpon_handler.delete_tcont(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001042
1043 @twisted_async
1044 def GetAllGemportsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001045 return self.core.xpon_handler.get_all_gemports_config_data(
1046 request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001047
1048 @twisted_async
1049 def CreateGemportsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001050 return self.core.xpon_handler.create_gem_port(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001051
1052 @twisted_async
1053 def UpdateGemportsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001054 return self.core.xpon_handler.update_gem_port(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001055
1056 @twisted_async
1057 def DeleteGemportsConfigData(self, request, context):
Nikolay Titov176f1db2017-08-10 12:38:43 -04001058 return self.core.xpon_handler.delete_gem_port(request, context)
Nikolay Titov3b31db92017-08-02 18:11:33 -04001059
1060 @twisted_async
1061 def GetAllMulticastGemportsConfigData(self, request, context):
1062 return AllMulticastGemportsConfigData()
1063
1064 @twisted_async
1065 def CreateMulticastGemportsConfigData(self, request, context):
1066 return Empty()
1067
1068 @twisted_async
1069 def UpdateMulticastGemportsConfigData(self, request, context):
1070 return Empty()
1071
1072 @twisted_async
1073 def DeleteMulticastGemportsConfigData(self, request, context):
1074 return Empty()
1075
1076 @twisted_async
1077 def GetAllMulticastDistributionSetData(self, request, context):
1078 return AllMulticastDistributionSetData()
1079
1080 @twisted_async
1081 def CreateMulticastDistributionSetData(self, request, context):
1082 return Empty()
1083
1084 @twisted_async
1085 def UpdateMulticastDistributionSetData(self, request, context):
1086 return Empty()
1087
1088 @twisted_async
1089 def DeleteMulticastDistributionSetData(self, request, context):
1090 return Empty()
Nikolay Titov89004ec2017-06-19 18:22:42 -04001091 # bbf_fiber rpcs end
1092
Zsolt Haraszti66862032016-11-28 14:28:39 -08001093 def StreamPacketsOut(self, request_iterator, context):
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001094 log.debug('start-stream-packets-out')
Zsolt Haraszti66862032016-11-28 14:28:39 -08001095
1096 @twisted_async
1097 def forward_packet_out(packet_out):
1098 agent = self.core.get_logical_device_agent(packet_out.id)
1099 agent.packet_out(packet_out.packet_out)
1100
1101 for request in request_iterator:
1102 forward_packet_out(packet_out=request)
1103
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001104 log.debug('stop-stream-packets-out')
1105
Zsolt Haraszti66862032016-11-28 14:28:39 -08001106 return Empty()
1107
1108 def ReceivePacketsIn(self, request, context):
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001109 log.debug('start-receive-packets-in')
1110 while self.ofagent_is_alive:
Zsolt Haraszti3300f742017-01-09 01:14:20 -08001111 try:
1112 packet_in = self.core.packet_in_queue.get(timeout=1)
1113 yield packet_in
1114 except QueueEmpty:
1115 if self.stopped:
1116 break
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001117 log.debug('stop-receive-packets-in')
Zsolt Haraszti66862032016-11-28 14:28:39 -08001118
1119 def send_packet_in(self, device_id, ofp_packet_in):
1120 """Must be called on the twisted thread"""
1121 packet_in = PacketIn(id=device_id, packet_in=ofp_packet_in)
1122 self.core.packet_in_queue.put(packet_in)
Zsolt Haraszti217a12e2016-12-19 16:37:55 -08001123
1124 def ReceiveChangeEvents(self, request, context):
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001125 log.debug('start-receive-change-events')
1126 while self.ofagent_is_alive:
Zsolt Haraszti3300f742017-01-09 01:14:20 -08001127 try:
1128 event = self.core.change_event_queue.get(timeout=1)
1129 yield event
1130 except QueueEmpty:
1131 if self.stopped:
1132 break
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001133 log.debug('stop-receive-change-events')
Zsolt Haraszti217a12e2016-12-19 16:37:55 -08001134
1135 def send_port_change_event(self, device_id, port_status):
1136 """Must be called on the twisted thread"""
1137 assert isinstance(port_status, ofp_port_status)
1138 event = ChangeEvent(id=device_id, port_status=port_status)
1139 self.core.change_event_queue.put(event)
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001140
1141
1142 @twisted_async
1143 def ListAlarmFilters(self, request, context):
1144 try:
1145 filters = self.root.get('/alarm_filters')
1146 return AlarmFilters(filters=filters)
1147 except KeyError:
1148 context.set_code(StatusCode.NOT_FOUND)
1149 return AlarmFilters()
1150
1151 @twisted_async
1152 def GetAlarmFilter(self, request, context):
1153 if '/' in request.id:
1154 context.set_details(
1155 'Malformed alarm filter id \'{}\''.format(request.id))
1156 context.set_code(StatusCode.INVALID_ARGUMENT)
1157 return AlarmFilter()
1158
1159 try:
1160 alarm_filter = self.root.get('/alarm_filters/{}'.format(request.id))
khenaidoo08d48d22017-06-29 19:42:49 -04001161
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001162 return alarm_filter
1163 except KeyError:
1164 context.set_details(
1165 'Alarm filter \'{}\' not found'.format(request.id))
1166 context.set_code(StatusCode.NOT_FOUND)
1167 return AlarmFilter()
1168
1169 @twisted_async
1170 def DeleteAlarmFilter(self, request, context):
1171 if '/' in request.id:
1172 context.set_details(
1173 'Malformed alarm filter id \'{}\''.format(request.id))
1174 context.set_code(StatusCode.INVALID_ARGUMENT)
1175 return Empty()
1176
1177 try:
1178 self.root.remove('/alarm_filters/{}'.format(request.id))
1179 except KeyError:
1180 context.set_code(StatusCode.NOT_FOUND)
1181
1182 return Empty()
1183
1184 @twisted_async
1185 def CreateAlarmFilter(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -04001186 log.debug('grpc-request', request=request)
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001187
1188 try:
1189 assert isinstance(request, AlarmFilter)
1190 alarm_filter = request
khenaidoo08d48d22017-06-29 19:42:49 -04001191 assert alarm_filter.id is not None, 'Local Alarm filter to be ' \
1192 'created must have id'
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001193 except AssertionError, e:
1194 context.set_details(e.message)
1195 context.set_code(StatusCode.INVALID_ARGUMENT)
1196 return AlarmFilter()
1197
Stephane Barbarie4db8ca22017-04-24 10:30:20 -04001198 # add device to tree
1199 self.root.add('/alarm_filters', alarm_filter)
1200
1201 return request
1202
1203 @twisted_async
1204 def UpdateAlarmFilter(self, request, context):
1205 if '/' in request.id:
1206 context.set_details(
1207 'Malformed alarm filter id \'{}\''.format(request.id))
1208 context.set_code(StatusCode.INVALID_ARGUMENT)
1209 return AlarmFilter()
1210
1211 try:
1212 assert isinstance(request, AlarmFilter)
1213 alarm_filter = self.root.get('/alarm_filters/{}'.format(request.id))
1214 self.root.update('/alarm_filters/{}'.format(request.id), request)
1215
1216 return request
1217 except KeyError:
1218 context.set_details(
1219 'Alarm filter \'{}\' not found'.format(request.id))
1220 context.set_code(StatusCode.NOT_FOUND)
1221 return AlarmFilter()
ggowdru236bd952017-06-20 20:32:55 -07001222
1223 @twisted_async
1224 def GetImages(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -04001225 log.debug('grpc-request', request=request)
ggowdru236bd952017-06-20 20:32:55 -07001226
1227 if '/' in request.id:
1228 context.set_details(
1229 'Malformed device id \'{}\''.format(request.id))
1230 context.set_code(StatusCode.INVALID_ARGUMENT)
1231 return Images()
1232
1233 try:
1234 device = self.root.get('/devices/' + request.id)
1235 return device.images
1236
1237 except KeyError:
1238 context.set_details(
1239 'Device \'{}\' not found'.format(request.id))
1240 context.set_code(StatusCode.NOT_FOUND)
1241 return Images()
sathishg5ae86222017-06-28 15:16:29 +05301242
1243 @twisted_async
1244 def SelfTest(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -04001245 log.debug('grpc-request', request=request)
sathishg5ae86222017-06-28 15:16:29 +05301246
1247 if '/' in request.id:
1248 context.set_details(
1249 'Malformed device id \'{}\''.format(request.id))
1250 context.set_code(StatusCode.INVALID_ARGUMENT)
1251 return SelfTestResponse()
1252
1253 try:
1254 path = '/devices/{}'.format(request.id)
1255 device = self.root.get(path)
1256
1257 agent = self.core.get_device_agent(device.id)
1258 resp = agent.self_test(device)
1259 return resp.result
1260
1261 except KeyError:
1262 context.set_details(
1263 'Device \'{}\' not found'.format(request.id))
1264 context.set_code(StatusCode.NOT_FOUND)
1265 return SelfTestResponse()
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001266
1267 def _ofagent_session_termination(self):
1268 log.debug('start-ofagent-session-termination')
1269
1270 # Stop ofagent heartbeat
1271 if self.ofagent_heartbeat_lc is not None:
1272 self.ofagent_heartbeat_lc.stop()
1273
1274 # Reset flags and assignments
1275 self.ofagent_is_alive = False
1276 self.subscriber = None
1277 self.ofagent_heartbeat_count = 0
1278
1279 # Some local services will stop (packet-in/change-events)
1280 # need to re-register them
1281 registry('grpc_server').register(
1282 add_VolthaLocalServiceServicer_to_server, self)
1283
1284 log.debug('stop-ofagent-session-termination')
1285
1286 def _ofagent_session_heartbeat(self):
1287 log.debug('start-ofagent-heartbeat')
1288 if self.ofagent_heartbeat_count > self.ofagent_heartbeat_max_count:
1289 self._ofagent_session_termination()
1290 else:
1291 self.ofagent_heartbeat_count += 1
1292
1293 log.debug('stop-ofagent-heartbeat')
1294
1295 @twisted_async
1296 def Subscribe(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -04001297 log.debug('grpc-request', request=request)
Stephane Barbarie2940dac2017-08-18 14:15:17 -04001298
1299 # Check if an ofagent subscriber is assigned
1300 if self.subscriber is None:
1301 log.debug('ofagent-subscriber-request')
1302
1303 try:
1304 # Assign the request as the active subscriber
1305 self.subscriber = OfAgentSubscriber(
1306 ofagent_id=request.ofagent_id,
1307 voltha_id=self.instance_id
1308 )
1309
1310 # Start the hearbeat
1311 self.ofagent_heartbeat_count = 0
1312 self.ofagent_heartbeat_lc = task.LoopingCall(self._ofagent_session_heartbeat)
1313 self.ofagent_heartbeat_lc.start(self.ofagent_heartbeat_delay)
1314
1315 log.debug('ofagent-subscriber-connected', subscriber=self.subscriber)
1316
1317 except _Rendezvous, e:
1318 log.error('ofagent-subscriber-failure', exception=repr(e), status=e.code())
1319
1320 except Exception as e:
1321 log.exception('ofagent-subscriber-unexpected-failure', exception=repr(e))
1322
1323 elif self.subscriber.ofagent_id == request.ofagent_id:
1324 log.debug('ofagent-subscriber-matches-assigned',
1325 current=self.subscriber)
1326 # reset counter
1327 self.ofagent_heartbeat_count = 0
1328
1329 else:
1330 log.debug('ofagent-subscriber-not-matching-assigned',
1331 current=self.subscriber)
1332
1333 return self.subscriber
Chip Boling69abce82018-06-18 09:56:23 -05001334
1335 @twisted_async
1336 def GetMibDeviceData(self, request, context):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -04001337 log.debug('grpc-request', request=request)
Chip Boling69abce82018-06-18 09:56:23 -05001338
1339 depth = int(dict(context.invocation_metadata()).get('get-depth', -1))
1340
1341 if '/' in request.id:
1342 context.set_details(
1343 'Malformed device id \'{}\''.format(request.id))
1344 context.set_code(StatusCode.INVALID_ARGUMENT)
1345 return MibDeviceData()
1346
1347 try:
1348 return self.root.get('/omci_mibs/' + request.id, depth=depth)
1349
1350 except KeyError:
1351 context.set_details(
1352 'OMCI MIB for Device \'{}\' not found'.format(request.id))
1353 context.set_code(StatusCode.NOT_FOUND)
1354 return MibDeviceData()
1355
jasonhuang5f3e63b2018-07-27 01:32:48 +08001356 @twisted_async
1357 def GetAlarmDeviceData(self, request, context):
1358 log.info('grpc-request', request=request)
1359
1360 depth = int(dict(context.invocation_metadata()).get('get-depth', -1))
1361
1362 if '/' in request.id:
1363 context.set_details(
1364 'Malformed device id \'{}\''.format(request.id))
1365 context.set_code(StatusCode.INVALID_ARGUMENT)
1366 return AlarmDeviceData()
1367
1368 try:
1369 return self.root.get('/omci_alarms/' + request.id, depth=depth)
1370
1371 except KeyError:
1372 context.set_details(
1373 'OMCI ALARM for Device \'{}\' not found'.format(request.id))
1374 context.set_code(StatusCode.NOT_FOUND)
Scott Bakerd3190952018-09-04 15:47:28 -07001375 return AlarmDeviceData()
1376
1377 @twisted_async
1378 def SimulateAlarm(self, request, context):
1379 log.debug('grpc-request', request=request)
1380
1381 if '/' in request.id:
1382 context.set_details(
1383 'Malformed device id \'{}\''.format(request.id))
1384 context.set_code(StatusCode.INVALID_ARGUMENT)
1385 response = OperationResp(code=OperationResp.OPERATION_FAILURE)
1386 return response
1387
1388 try:
1389 path = '/devices/{}'.format(request.id)
1390 device = self.root.get(path)
1391 agent = self.core.get_device_agent(device.id)
1392 response = agent.simulate_alarm(device, request)
1393 return response
1394
1395 except KeyError:
1396 context.set_details(
1397 'Device \'{}\' not found'.format(request.id))
1398 context.set_code(StatusCode.NOT_FOUND)
1399 response = OperationResp(code=OperationResp.OPERATION_FAILURE)
1400 return response
1401 except Exception as e:
1402 log.exception(e.message)
1403 response = OperationResp(code=OperationResp.OPERATION_FAILURE)
1404 return response