| # |
| # 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] |