VOL-1395: Common shared libraries needed for Python based device adapters.
This is an initial check-in of code from the master branch. Additional work
is expected on a few items to work with the new go-core and will be covered
by separate JIRAs and commits.
Change-Id: I0856ec6b79b8d3e49082c609eb9c7eedd75b1708
diff --git a/python/adapters/extensions/omci/openomci_agent.py b/python/adapters/extensions/omci/openomci_agent.py
new file mode 100644
index 0000000..98ba684
--- /dev/null
+++ b/python/adapters/extensions/omci/openomci_agent.py
@@ -0,0 +1,283 @@
+#
+# Copyright 2017 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+import structlog
+from twisted.internet import reactor
+from voltha.extensions.omci.database.mib_db_dict import MibDbVolatileDict
+from voltha.extensions.omci.database.mib_db_ext import MibDbExternal
+from voltha.extensions.omci.state_machines.mib_sync import MibSynchronizer
+from voltha.extensions.omci.tasks.mib_upload import MibUploadTask
+from voltha.extensions.omci.tasks.get_mds_task import GetMdsTask
+from voltha.extensions.omci.tasks.mib_resync_task import MibResyncTask
+from voltha.extensions.omci.tasks.mib_reconcile_task import MibReconcileTask
+from voltha.extensions.omci.tasks.sync_time_task import SyncTimeTask
+from voltha.extensions.omci.state_machines.alarm_sync import AlarmSynchronizer
+from voltha.extensions.omci.tasks.alarm_resync_task import AlarmResyncTask
+from voltha.extensions.omci.database.alarm_db_ext import AlarmDbExternal
+from voltha.extensions.omci.tasks.interval_data_task import IntervalDataTask
+from voltha.extensions.omci.onu_device_entry import OnuDeviceEntry
+from voltha.extensions.omci.state_machines.omci_onu_capabilities import OnuOmciCapabilities
+from voltha.extensions.omci.tasks.onu_capabilities_task import OnuCapabilitiesTask
+from voltha.extensions.omci.state_machines.performance_intervals import PerformanceIntervals
+from voltha.extensions.omci.tasks.omci_create_pm_task import OmciCreatePMRequest
+from voltha.extensions.omci.tasks.omci_delete_pm_task import OmciDeletePMRequest
+from voltha.extensions.omci.state_machines.image_agent import ImageDownloadeSTM, OmciSoftwareImageDownloadSTM
+from voltha.extensions.omci.tasks.file_download_task import FileDownloadTask
+from voltha.extensions.omci.tasks.omci_sw_image_upgrade_task import OmciSwImageUpgradeTask
+
+OpenOmciAgentDefaults = {
+ 'mib-synchronizer': {
+ 'state-machine': MibSynchronizer, # Implements the MIB synchronization state machine
+ 'database': MibDbVolatileDict, # Implements volatile ME MIB database
+ #'database': MibDbExternal, # Implements persistent ME MIB database
+ 'advertise-events': True, # Advertise events on OpenOMCI event bus
+ 'tasks': {
+ 'mib-upload': MibUploadTask,
+ 'get-mds': GetMdsTask,
+ 'mib-audit': GetMdsTask,
+ 'mib-resync': MibResyncTask,
+ 'mib-reconcile': MibReconcileTask
+ }
+ },
+ 'omci-capabilities': {
+ 'state-machine': OnuOmciCapabilities, # Implements OMCI capabilities state machine
+ 'advertise-events': False, # Advertise events on OpenOMCI event bus
+ 'tasks': {
+ 'get-capabilities': OnuCapabilitiesTask # Get supported ME and Commands
+ }
+ },
+ 'performance-intervals': {
+ 'state-machine': PerformanceIntervals, # Implements PM Intervals State machine
+ 'advertise-events': False, # Advertise events on OpenOMCI event bus
+ 'tasks': {
+ 'sync-time': SyncTimeTask,
+ 'collect-data': IntervalDataTask,
+ 'create-pm': OmciCreatePMRequest,
+ 'delete-pm': OmciDeletePMRequest,
+ },
+ },
+ 'alarm-synchronizer': {
+ 'state-machine': AlarmSynchronizer, # Implements the Alarm sync state machine
+ 'database': AlarmDbExternal, # For any State storage needs
+ 'advertise-events': True, # Advertise events on OpenOMCI event bus
+ 'tasks': {
+ 'alarm-resync': AlarmResyncTask
+ }
+ },
+ 'image_downloader': {
+ 'state-machine': ImageDownloadeSTM,
+ 'advertise-event': True,
+ 'tasks': {
+ 'download-file': FileDownloadTask
+ }
+ },
+ 'image_upgrader': {
+ 'state-machine': OmciSoftwareImageDownloadSTM,
+ 'advertise-event': True,
+ 'tasks': {
+ 'omci_upgrade_task': OmciSwImageUpgradeTask
+ }
+ }
+ # 'image_activator': {
+ # 'state-machine': OmciSoftwareImageActivateSTM,
+ # 'advertise-event': True,
+ # }
+}
+
+
+class OpenOMCIAgent(object):
+ """
+ OpenOMCI for VOLTHA
+
+ This will become the primary interface into OpenOMCI for ONU Device Adapters
+ in VOLTHA v1.3 sprint 3 time frame.
+ """
+ def __init__(self, core, support_classes=OpenOmciAgentDefaults, clock=None):
+ """
+ Class initializer
+
+ :param core: (VolthaCore) VOLTHA Core
+ :param support_classes: (Dict) Classes to support OMCI
+ """
+ self.log = structlog.get_logger()
+ self._core = core
+ self.reactor = clock if clock is not None else reactor
+ self._started = False
+ self._devices = dict() # device-id -> DeviceEntry
+ self._event_bus = None
+
+ # OMCI related databases are on a per-agent basis. State machines and tasks
+ # are per ONU Vendore
+ #
+ # MIB Synchronization Database
+ self._mib_db = None
+ self._mib_database_cls = support_classes['mib-synchronizer']['database']
+
+ # Alarm Synchronization Database
+ self._alarm_db = None
+ self._alarm_database_cls = support_classes['alarm-synchronizer']['database']
+
+ @property
+ def core(self):
+ """ Return a reference to the VOLTHA Core component"""
+ return self._core
+
+ @property
+ def database_class(self):
+ return self._mib_database_cls
+
+ # TODO: Need to deprecate this. ImageAgent is using it and should not
+ @property
+ def database(self):
+ return self._mib_db
+
+ def start(self):
+ """
+ Start OpenOMCI
+ """
+ if self._started:
+ return
+
+ self.log.debug('OpenOMCIAgent.start')
+ self._started = True
+
+ try:
+ # Create all databases as needed. This should be done before
+ # State machines are started for the first time
+
+ if self._mib_db is None:
+ self._mib_db = self._mib_database_cls(self)
+
+ if self._alarm_db is None:
+ self._alarm_db = self._alarm_database_cls(self)
+
+ # Start/restore databases
+
+ self._mib_db.start()
+ self._alarm_db.start()
+
+ for device in self._devices.itervalues():
+ device.start()
+
+ except Exception as e:
+ self.log.exception('startup', e=e)
+
+ def stop(self):
+ """
+ Shutdown OpenOMCI
+ """
+ if not self._started:
+ return
+
+ self.log.debug('stop')
+ self._started = False
+ self._event_bus = None
+
+ # ONUs OMCI shutdown
+ for device in self._devices.itervalues():
+ device.stop()
+
+ # DB shutdown
+ self._mib_db.stop()
+ self._alarm_db.stop()
+
+ def mk_event_bus(self):
+ """ Get the event bus for OpenOMCI"""
+ if self._event_bus is None:
+ from voltha.extensions.omci.openomci_event_bus import OpenOmciEventBus
+ self._event_bus = OpenOmciEventBus()
+
+ return self._event_bus
+
+ def advertise(self, event_type, data):
+ """
+ Advertise an OpenOMCU event on the kafka bus
+ :param event_type: (int) Event Type (enumberation from OpenOMCI protobuf definitions)
+ :param data: (Message, dict, ...) Associated data (will be convert to a string)
+ """
+ if self._started:
+ try:
+ self.mk_event_bus().advertise(event_type, data)
+
+ except Exception as e:
+ self.log.exception('advertise-failure', e=e)
+
+ def add_device(self, device_id, adapter_agent, custom_me_map=None,
+ support_classes=OpenOmciAgentDefaults):
+ """
+ Add a new ONU to be managed.
+
+ To provide vendor-specific or custom Managed Entities, create your own Entity
+ ID to class mapping dictionary.
+
+ Since ONU devices can be added at any time (even during Device Handler
+ startup), the ONU device handler is responsible for calling start()/stop()
+ for this object.
+
+ :param device_id: (str) Device ID of ONU to add
+ :param adapter_agent: (AdapterAgent) Adapter agent for ONU
+ :param custom_me_map: (dict) Additional/updated ME to add to class map
+ :param support_classes: (dict) State machines and tasks for this ONU
+
+ :return: (OnuDeviceEntry) The ONU device
+ """
+ self.log.debug('OpenOMCIAgent.add-device', device_id=device_id)
+
+ device = self._devices.get(device_id)
+
+ if device is None:
+ device = OnuDeviceEntry(self, device_id, adapter_agent, custom_me_map,
+ self._mib_db, self._alarm_db, support_classes, clock=self.reactor)
+
+ self._devices[device_id] = device
+
+ return device
+
+ def remove_device(self, device_id, cleanup=False):
+ """
+ Remove a managed ONU
+
+ :param device_id: (str) Device ID of ONU to remove
+ :param cleanup: (bool) If true, scrub any state related information
+ """
+ self.log.debug('remove-device', device_id=device_id, cleanup=cleanup)
+
+ device = self._devices.get(device_id)
+
+ if device is not None:
+ device.stop()
+
+ if cleanup:
+ del self._devices[device_id]
+
+ def device_ids(self):
+ """
+ Get an immutable set of device IDs managed by this OpenOMCI instance
+
+ :return: (frozenset) Set of device IDs (str)
+ """
+ return frozenset(self._devices.keys())
+
+ def get_device(self, device_id):
+ """
+ Get ONU device entry. For external (non-OpenOMCI users) the ONU Device
+ returned should be used for read-only activity.
+
+ :param device_id: (str) ONU Device ID
+
+ :return: (OnuDeviceEntry) ONU Device entry
+ :raises KeyError: If device does not exist
+ """
+ return self._devices[device_id]