blob: 98ba6840f21e2bdf8c2b8b1dde0f26ec3ab7c81d [file] [log] [blame]
Chip Boling32aab302019-01-23 10:50:18 -06001#
2# Copyright 2017 the original author or authors.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16import structlog
17from twisted.internet import reactor
18from voltha.extensions.omci.database.mib_db_dict import MibDbVolatileDict
19from voltha.extensions.omci.database.mib_db_ext import MibDbExternal
20from voltha.extensions.omci.state_machines.mib_sync import MibSynchronizer
21from voltha.extensions.omci.tasks.mib_upload import MibUploadTask
22from voltha.extensions.omci.tasks.get_mds_task import GetMdsTask
23from voltha.extensions.omci.tasks.mib_resync_task import MibResyncTask
24from voltha.extensions.omci.tasks.mib_reconcile_task import MibReconcileTask
25from voltha.extensions.omci.tasks.sync_time_task import SyncTimeTask
26from voltha.extensions.omci.state_machines.alarm_sync import AlarmSynchronizer
27from voltha.extensions.omci.tasks.alarm_resync_task import AlarmResyncTask
28from voltha.extensions.omci.database.alarm_db_ext import AlarmDbExternal
29from voltha.extensions.omci.tasks.interval_data_task import IntervalDataTask
30from voltha.extensions.omci.onu_device_entry import OnuDeviceEntry
31from voltha.extensions.omci.state_machines.omci_onu_capabilities import OnuOmciCapabilities
32from voltha.extensions.omci.tasks.onu_capabilities_task import OnuCapabilitiesTask
33from voltha.extensions.omci.state_machines.performance_intervals import PerformanceIntervals
34from voltha.extensions.omci.tasks.omci_create_pm_task import OmciCreatePMRequest
35from voltha.extensions.omci.tasks.omci_delete_pm_task import OmciDeletePMRequest
36from voltha.extensions.omci.state_machines.image_agent import ImageDownloadeSTM, OmciSoftwareImageDownloadSTM
37from voltha.extensions.omci.tasks.file_download_task import FileDownloadTask
38from voltha.extensions.omci.tasks.omci_sw_image_upgrade_task import OmciSwImageUpgradeTask
39
40OpenOmciAgentDefaults = {
41 'mib-synchronizer': {
42 'state-machine': MibSynchronizer, # Implements the MIB synchronization state machine
43 'database': MibDbVolatileDict, # Implements volatile ME MIB database
44 #'database': MibDbExternal, # Implements persistent ME MIB database
45 'advertise-events': True, # Advertise events on OpenOMCI event bus
46 'tasks': {
47 'mib-upload': MibUploadTask,
48 'get-mds': GetMdsTask,
49 'mib-audit': GetMdsTask,
50 'mib-resync': MibResyncTask,
51 'mib-reconcile': MibReconcileTask
52 }
53 },
54 'omci-capabilities': {
55 'state-machine': OnuOmciCapabilities, # Implements OMCI capabilities state machine
56 'advertise-events': False, # Advertise events on OpenOMCI event bus
57 'tasks': {
58 'get-capabilities': OnuCapabilitiesTask # Get supported ME and Commands
59 }
60 },
61 'performance-intervals': {
62 'state-machine': PerformanceIntervals, # Implements PM Intervals State machine
63 'advertise-events': False, # Advertise events on OpenOMCI event bus
64 'tasks': {
65 'sync-time': SyncTimeTask,
66 'collect-data': IntervalDataTask,
67 'create-pm': OmciCreatePMRequest,
68 'delete-pm': OmciDeletePMRequest,
69 },
70 },
71 'alarm-synchronizer': {
72 'state-machine': AlarmSynchronizer, # Implements the Alarm sync state machine
73 'database': AlarmDbExternal, # For any State storage needs
74 'advertise-events': True, # Advertise events on OpenOMCI event bus
75 'tasks': {
76 'alarm-resync': AlarmResyncTask
77 }
78 },
79 'image_downloader': {
80 'state-machine': ImageDownloadeSTM,
81 'advertise-event': True,
82 'tasks': {
83 'download-file': FileDownloadTask
84 }
85 },
86 'image_upgrader': {
87 'state-machine': OmciSoftwareImageDownloadSTM,
88 'advertise-event': True,
89 'tasks': {
90 'omci_upgrade_task': OmciSwImageUpgradeTask
91 }
92 }
93 # 'image_activator': {
94 # 'state-machine': OmciSoftwareImageActivateSTM,
95 # 'advertise-event': True,
96 # }
97}
98
99
100class OpenOMCIAgent(object):
101 """
102 OpenOMCI for VOLTHA
103
104 This will become the primary interface into OpenOMCI for ONU Device Adapters
105 in VOLTHA v1.3 sprint 3 time frame.
106 """
107 def __init__(self, core, support_classes=OpenOmciAgentDefaults, clock=None):
108 """
109 Class initializer
110
111 :param core: (VolthaCore) VOLTHA Core
112 :param support_classes: (Dict) Classes to support OMCI
113 """
114 self.log = structlog.get_logger()
115 self._core = core
116 self.reactor = clock if clock is not None else reactor
117 self._started = False
118 self._devices = dict() # device-id -> DeviceEntry
119 self._event_bus = None
120
121 # OMCI related databases are on a per-agent basis. State machines and tasks
122 # are per ONU Vendore
123 #
124 # MIB Synchronization Database
125 self._mib_db = None
126 self._mib_database_cls = support_classes['mib-synchronizer']['database']
127
128 # Alarm Synchronization Database
129 self._alarm_db = None
130 self._alarm_database_cls = support_classes['alarm-synchronizer']['database']
131
132 @property
133 def core(self):
134 """ Return a reference to the VOLTHA Core component"""
135 return self._core
136
137 @property
138 def database_class(self):
139 return self._mib_database_cls
140
141 # TODO: Need to deprecate this. ImageAgent is using it and should not
142 @property
143 def database(self):
144 return self._mib_db
145
146 def start(self):
147 """
148 Start OpenOMCI
149 """
150 if self._started:
151 return
152
153 self.log.debug('OpenOMCIAgent.start')
154 self._started = True
155
156 try:
157 # Create all databases as needed. This should be done before
158 # State machines are started for the first time
159
160 if self._mib_db is None:
161 self._mib_db = self._mib_database_cls(self)
162
163 if self._alarm_db is None:
164 self._alarm_db = self._alarm_database_cls(self)
165
166 # Start/restore databases
167
168 self._mib_db.start()
169 self._alarm_db.start()
170
171 for device in self._devices.itervalues():
172 device.start()
173
174 except Exception as e:
175 self.log.exception('startup', e=e)
176
177 def stop(self):
178 """
179 Shutdown OpenOMCI
180 """
181 if not self._started:
182 return
183
184 self.log.debug('stop')
185 self._started = False
186 self._event_bus = None
187
188 # ONUs OMCI shutdown
189 for device in self._devices.itervalues():
190 device.stop()
191
192 # DB shutdown
193 self._mib_db.stop()
194 self._alarm_db.stop()
195
196 def mk_event_bus(self):
197 """ Get the event bus for OpenOMCI"""
198 if self._event_bus is None:
199 from voltha.extensions.omci.openomci_event_bus import OpenOmciEventBus
200 self._event_bus = OpenOmciEventBus()
201
202 return self._event_bus
203
204 def advertise(self, event_type, data):
205 """
206 Advertise an OpenOMCU event on the kafka bus
207 :param event_type: (int) Event Type (enumberation from OpenOMCI protobuf definitions)
208 :param data: (Message, dict, ...) Associated data (will be convert to a string)
209 """
210 if self._started:
211 try:
212 self.mk_event_bus().advertise(event_type, data)
213
214 except Exception as e:
215 self.log.exception('advertise-failure', e=e)
216
217 def add_device(self, device_id, adapter_agent, custom_me_map=None,
218 support_classes=OpenOmciAgentDefaults):
219 """
220 Add a new ONU to be managed.
221
222 To provide vendor-specific or custom Managed Entities, create your own Entity
223 ID to class mapping dictionary.
224
225 Since ONU devices can be added at any time (even during Device Handler
226 startup), the ONU device handler is responsible for calling start()/stop()
227 for this object.
228
229 :param device_id: (str) Device ID of ONU to add
230 :param adapter_agent: (AdapterAgent) Adapter agent for ONU
231 :param custom_me_map: (dict) Additional/updated ME to add to class map
232 :param support_classes: (dict) State machines and tasks for this ONU
233
234 :return: (OnuDeviceEntry) The ONU device
235 """
236 self.log.debug('OpenOMCIAgent.add-device', device_id=device_id)
237
238 device = self._devices.get(device_id)
239
240 if device is None:
241 device = OnuDeviceEntry(self, device_id, adapter_agent, custom_me_map,
242 self._mib_db, self._alarm_db, support_classes, clock=self.reactor)
243
244 self._devices[device_id] = device
245
246 return device
247
248 def remove_device(self, device_id, cleanup=False):
249 """
250 Remove a managed ONU
251
252 :param device_id: (str) Device ID of ONU to remove
253 :param cleanup: (bool) If true, scrub any state related information
254 """
255 self.log.debug('remove-device', device_id=device_id, cleanup=cleanup)
256
257 device = self._devices.get(device_id)
258
259 if device is not None:
260 device.stop()
261
262 if cleanup:
263 del self._devices[device_id]
264
265 def device_ids(self):
266 """
267 Get an immutable set of device IDs managed by this OpenOMCI instance
268
269 :return: (frozenset) Set of device IDs (str)
270 """
271 return frozenset(self._devices.keys())
272
273 def get_device(self, device_id):
274 """
275 Get ONU device entry. For external (non-OpenOMCI users) the ONU Device
276 returned should be used for read-only activity.
277
278 :param device_id: (str) ONU Device ID
279
280 :return: (OnuDeviceEntry) ONU Device entry
281 :raises KeyError: If device does not exist
282 """
283 return self._devices[device_id]