vOL-1136: ADTRAN OLT: Support new shared KPI and Alarm libraries
Change-Id: Ief963b73f232e79862f39912184588abe88de24f
diff --git a/voltha/adapters/adtran_olt/adtran_device_handler.py b/voltha/adapters/adtran_olt/adtran_device_handler.py
index 438cb62..5fd5547 100644
--- a/voltha/adapters/adtran_olt/adtran_device_handler.py
+++ b/voltha/adapters/adtran_olt/adtran_device_handler.py
@@ -32,8 +32,8 @@
from voltha.protos.logical_device_pb2 import LogicalDevice
from voltha.protos.openflow_13_pb2 import ofp_desc, ofp_switch_features, OFPC_PORT_STATS, \
OFPC_GROUP_STATS, OFPC_TABLE_STATS, OFPC_FLOW_STATS
-from alarms.adapter_alarms import AdapterAlarms
-from pki.olt_pm_metrics import OltPmMetrics
+from voltha.extensions.alarms.adapter_alarms import AdapterAlarms
+from voltha.extensions.pki.olt.olt_pm_metrics import OltPmMetrics
from common.utils.asleep import asleep
_ = third_party
@@ -105,7 +105,7 @@
self.multicast_vlans = [DEFAULT_MULTICAST_VLAN]
self.untagged_vlan = DEFAULT_UNTAGGED_VLAN
self.utility_vlan = DEFAULT_UTILITY_VLAN
- self.default_mac_addr = '00:13:95:00:00:00'
+ self.mac_address = '00:13:95:00:00:00'
self._rest_support = None
# Northbound and Southbound ports
@@ -450,9 +450,16 @@
device.reason = 'Setting up PM configuration'
self.adapter_agent.update_device(device)
- self.pm_metrics = OltPmMetrics(self, device, grouped=True, freq_override=False)
+ kwargs = {
+ 'nni-ports': self.northbound_ports.values(),
+ 'pon-ports': self.southbound_ports.values()
+ }
+ self.pm_metrics = OltPmMetrics(self.adapter_agent, self.device_id,
+ grouped=True, freq_override=False,
+ **kwargs)
+
pm_config = self.pm_metrics.make_proto()
- self.log.info("initial-pm-config", pm_config=pm_config)
+ self.log.debug("initial-pm-config", pm_config=pm_config)
self.adapter_agent.update_device_pm_config(pm_config, init=True)
except Exception as e:
@@ -460,14 +467,6 @@
self.activate_failed(device, e.message)
############################################################################
- # Setup Alarm handler
-
- device.reason = 'Setting up Adapter Alarms'
- self.adapter_agent.update_device(device)
-
- self.alarms = AdapterAlarms(self.adapter, device.id)
-
- ############################################################################
# Set the ports in a known good initial state
if not reconciling:
try:
@@ -494,6 +493,14 @@
self.activate_failed(device, e.message)
############################################################################
+ # Setup Alarm handler
+
+ device.reason = 'Setting up Adapter Alarms'
+ self.adapter_agent.update_device(device)
+
+ self.alarms = AdapterAlarms(self.adapter_agent, device.id, ld_initialized.id)
+
+ ############################################################################
# Register for ONU detection
# self.adapter_agent.register_for_onu_detect_state(device.id)
@@ -520,7 +527,7 @@
self.logical_device_id = ld_initialized.id
# Start collecting stats from the device after a brief pause
- reactor.callLater(10, self.start_kpi_collection, device.id)
+ reactor.callLater(10, self.pm_metrics.start_collector)
# Signal completion
self.log.info('activated')
@@ -651,7 +658,7 @@
root_device_id=device.id)
ld_initialized = self.adapter_agent.create_logical_device(ld,
- dpid=self.default_mac_addr)
+ dpid=self.mac_address)
return ld_initialized
@inlineCallbacks
@@ -699,6 +706,9 @@
from flow.flow_entry import FlowEntry
FlowEntry.clear_all(device.id)
+ from download import Download
+ Download.clear_all(self.netconf_client)
+
# Start/stop the interfaces as needed. These are deferred calls
dl = []
@@ -1215,33 +1225,6 @@
self.log.info('update_pm_config', pm_config=pm_config)
self.pm_metrics.update(pm_config)
- def start_kpi_collection(self, device_id):
- # TODO: This has not been tested
- def _collect(device_id, prefix):
- from voltha.protos.events_pb2 import KpiEvent, KpiEventType, MetricValuePairs
-
- try:
- # Step 1: gather metrics from device
- port_metrics = self.pm_metrics.collect_port_metrics()
-
- # Step 2: prepare the KpiEvent for submission
- # we can time-stamp them here or could use time derived from OLT
- ts = arrow.utcnow().timestamp
- kpi_event = KpiEvent(
- type=KpiEventType.slice,
- ts=ts,
- prefixes={
- prefix + '.{}'.format(k): MetricValuePairs(metrics=port_metrics[k])
- for k in port_metrics.keys()}
- )
- # Step 3: submit
- self.adapter_agent.submit_kpis(kpi_event)
-
- except Exception as e:
- self.log.exception('failed-to-submit-kpis', e=e)
-
- self.pm_metrics.start_collector(_collect)
-
@inlineCallbacks
def get_device_info(self, device):
"""
@@ -1285,7 +1268,7 @@
device = self.adapter_agent.get_device(self.device_id)
try:
- from alarms.heartbeat_alarm import HeartbeatAlarm
+ from voltha.extensions.alarms.heartbeat_alarm import HeartbeatAlarm
if self.heartbeat_miss >= self.heartbeat_failed_limit:
if device.connect_status == ConnectStatus.REACHABLE:
@@ -1294,7 +1277,7 @@
device.oper_status = OperStatus.FAILED
device.reason = self.heartbeat_last_reason
self.adapter_agent.update_device(device)
- HeartbeatAlarm(self, 'olt', self.heartbeat_miss).raise_alarm()
+ HeartbeatAlarm(self.alarms, 'olt', self.heartbeat_miss).raise_alarm()
self.on_heatbeat_alarm(True)
else:
# Update device states
@@ -1303,7 +1286,7 @@
device.oper_status = OperStatus.ACTIVE
device.reason = ''
self.adapter_agent.update_device(device)
- HeartbeatAlarm(self, 'olt').clear_alarm()
+ HeartbeatAlarm(self.alarms, 'olt').clear_alarm()
self.on_heatbeat_alarm(False)
if self.netconf_client is None or not self.netconf_client.connected:
diff --git a/voltha/adapters/adtran_olt/adtran_olt.py b/voltha/adapters/adtran_olt/adtran_olt.py
index 9b846f0..6006755 100644
--- a/voltha/adapters/adtran_olt/adtran_olt.py
+++ b/voltha/adapters/adtran_olt/adtran_olt.py
@@ -41,7 +41,8 @@
DeviceType(
id=name,
adapter=name,
- accepts_bulk_flow_update=True
+ accepts_bulk_flow_update=True,
+ accepts_add_remove_flow_updates=False # TODO: Support flow-mods
)
]
@@ -50,8 +51,8 @@
self.config = config
self.descriptor = Adapter(
id=self.name,
- vendor='Adtran, Inc.',
- version='0.16',
+ vendor='Adtran Inc.',
+ version='0.17',
config=AdapterConfig(log_level=LogLevel.INFO)
)
log.debug('adtran_olt.__init__', adapter_agent=adapter_agent)
diff --git a/voltha/adapters/adtran_olt/adtran_olt_handler.py b/voltha/adapters/adtran_olt/adtran_olt_handler.py
index 3b334e8..3864c9b 100644
--- a/voltha/adapters/adtran_olt/adtran_olt_handler.py
+++ b/voltha/adapters/adtran_olt/adtran_olt_handler.py
@@ -225,8 +225,9 @@
command = "ip -o link | grep eth0 | sed -n -e 's/^.*ether //p' | awk '{ print $1 }'"
rcmd = RCmd(self.ip_address, self.netconf_username, self.netconf_password,
command)
- self.default_mac_addr = yield rcmd.execute()
- self.log.info("mac-addr", mac_addr=self.default_mac_addr)
+ address = yield rcmd.execute()
+ self.mac_address = address.replace('\n', '')
+ self.log.info("mac-addr", mac_addr=self.mac_address)
except Exception as e:
log.exception('mac-address', e=e)
diff --git a/voltha/adapters/adtran_olt/alarms/__init__.py b/voltha/adapters/adtran_olt/alarms/__init__.py
deleted file mode 100644
index b0fb0b2..0000000
--- a/voltha/adapters/adtran_olt/alarms/__init__.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2017-present Open Networking Foundation
-#
-# 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.
diff --git a/voltha/adapters/adtran_olt/alarms/adapter_alarms.py b/voltha/adapters/adtran_olt/alarms/adapter_alarms.py
deleted file mode 100644
index d74f726..0000000
--- a/voltha/adapters/adtran_olt/alarms/adapter_alarms.py
+++ /dev/null
@@ -1,133 +0,0 @@
-#
-# 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
-import arrow
-from voltha.protos.events_pb2 import AlarmEventType, \
- AlarmEventSeverity, AlarmEventState, AlarmEventCategory
-
-# TODO: In the device adapter, the following alarms are still TBD
-# (Taken from microsemi, so mileage may vare
-# ON_ALARM_SOFTWARE_ERROR = 0
-# PON_ALARM_LOS = 1
-# PON_ALARM_LOSI = 2
-# PON_ALARM_DOWI = 3
-# PON_ALARM_LOFI = 4
-# PON_ALARM_RDII = 5
-# PON_ALARM_LOAMI = 6
-# PON_ALARM_LCDGI = 7
-# PON_ALARM_LOAI = 8
-# PON_ALARM_SDI = 9
-# PON_ALARM_SFI = 10
-# PON_ALARM_PEE = 11
-# PON_ALARM_DGI = 12
-# PON_ALARM_LOKI = 13
-# PON_ALARM_TIWI = 14
-# PON_ALARM_TIA = 15
-# PON_ALARM_VIRTUAL_SCOPE_ONU_LASER_ALWAYS_ON = 16
-# PON_ALARM_VIRTUAL_SCOPE_ONU_SIGNAL_DEGRADATION = 17
-# PON_ALARM_VIRTUAL_SCOPE_ONU_EOL = 18
-# PON_ALARM_VIRTUAL_SCOPE_ONU_EOL_DATABASE_IS_FULL = 19
-# PON_ALARM_AUTH_FAILED_IN_REGISTRATION_ID_MODE = 20
-# PON_ALARM_SUFI = 21
-
-
-class AdapterAlarms:
- def __init__(self, adapter, device_id):
- self.log = structlog.get_logger(device_id=device_id)
- self.adapter = adapter
- self.device_id = device_id
- self.lc = None
-
- def format_id(self, alarm):
- return 'voltha.{}.{}.{}'.format(self.adapter.name,
- self.device_id,
- alarm)
-
- def format_description(self, _object, alarm, status):
- return '{} Alarm - {} - {}'.format(_object.upper(),
- alarm.upper(),
- 'Raised' if status else 'Cleared')
-
- def send_alarm(self, context_data, alarm_data):
- try:
- current_context = {}
-
- if isinstance(context_data, dict):
- for key, value in context_data.iteritems():
- current_context[key] = str(value)
-
- alarm_event = self.adapter.adapter_agent.create_alarm(
- id=alarm_data.get('id', 'voltha.{}.{}.olt'.format(self.adapter.name,
- self.device_id)),
- resource_id=str(alarm_data.get('resource_id', self.device_id)),
- description="{}.{} - {}".format(self.adapter.name, self.device_id,
- alarm_data.get('description')),
- type=alarm_data.get('type'),
- category=alarm_data.get('category'),
- severity=alarm_data.get('severity'),
- state=alarm_data.get('state'),
- raised_ts=alarm_data.get('ts', 0),
- context=current_context
- )
- self.adapter.adapter_agent.submit_alarm(self.device_id, alarm_event)
-
- except Exception as e:
- self.log.exception('failed-to-send-alarm', e=e)
-
-
-class AlarmBase(object):
- def __init__(self, handler, object_type, alarm,
- alarm_category,
- resource_id=None,
- alarm_type=AlarmEventType.EQUIPMENT,
- alarm_severity=AlarmEventSeverity.CRITICAL):
-
- self._handler = handler
- self._object_type = object_type
- self._alarm = alarm
- self._alarm_category = alarm_category
- self._alarm_type = alarm_type
- self._alarm_severity = alarm_severity
- self._resource_id = resource_id
-
- def get_alarm_data(self, status):
- data = {
- 'ts': arrow.utcnow().timestamp,
- 'description': self._handler.alarms.format_description(self._object_type,
- self._alarm,
- status),
- 'id': self._handler.alarms.format_id(self._alarm),
- 'type': self._alarm_type,
- 'category': self._alarm_category,
- 'severity': self._alarm_severity,
- 'state': AlarmEventState.RAISED if status else AlarmEventState.CLEARED
- }
- if self._resource_id is not None:
- data['resource_id'] = self._resource_id
- return data
-
- def get_context_data(self):
- return {} # You should override this if needed
-
- def raise_alarm(self):
- alarm_data = self.get_alarm_data(True)
- context_data = self.get_context_data()
- self._handler.alarms.send_alarm(context_data, alarm_data)
-
- def clear_alarm(self):
- alarm_data = self.get_alarm_data(False)
- context_data = self.get_context_data()
- self._handler.alarms.send_alarm(context_data, alarm_data)
diff --git a/voltha/adapters/adtran_olt/alarms/heartbeat_alarm.py b/voltha/adapters/adtran_olt/alarms/heartbeat_alarm.py
deleted file mode 100644
index 418867f..0000000
--- a/voltha/adapters/adtran_olt/alarms/heartbeat_alarm.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright 2017-present Adtran, Inc.
-#
-# 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.
-from voltha.protos.events_pb2 import AlarmEventType, AlarmEventSeverity, AlarmEventCategory
-from adapter_alarms import AlarmBase
-
-
-class HeartbeatAlarm(AlarmBase):
- def __init__(self, handler, object_type='olt', heartbeat_misses=0):
- super(HeartbeatAlarm, self).__init__(handler, object_type,
- alarm='Heartbeat',
- alarm_category=AlarmEventCategory.PON,
- alarm_type=AlarmEventType.EQUIPMENT,
- alarm_severity=AlarmEventSeverity.CRITICAL)
- self._misses = heartbeat_misses
-
- def get_context_data(self):
- return {'heartbeats-missed': self._misses}
-
diff --git a/voltha/adapters/adtran_olt/alarms/onu_active_alarm.py b/voltha/adapters/adtran_olt/alarms/onu_active_alarm.py
deleted file mode 100644
index 61e6825..0000000
--- a/voltha/adapters/adtran_olt/alarms/onu_active_alarm.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright 2017-present Adtran, Inc.
-#
-# 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.
-
-from adapter_alarms import AlarmBase
-from voltha.protos.events_pb2 import AlarmEventType, AlarmEventSeverity, AlarmEventCategory
-
-
-class OnuActiveAlarm(AlarmBase):
- def __init__(self, handler, pon_id, serial_number, reg_id):
- super(OnuActiveAlarm, self).__init__(handler, 'ONU',
- alarm='ONU_ACTIVATED',
- alarm_category=AlarmEventCategory.PON,
- resource_id=pon_id,
- alarm_type=AlarmEventType.EQUIPMENT,
- alarm_severity=AlarmEventSeverity.CRITICAL)
- self._pon_id = pon_id
- self._serial_number = serial_number
- self._device_id = handler.device_id
- device = handler.adapter_agent.get_device(handler.device_id)
- self._olt_serial_number = device.serial_number
- self._host = device.ipv4_address
- self._datapath_id = device.parent_id
- self._reg_id = reg_id
-
- def get_context_data(self):
- return {
- 'pon-id': self._pon_id,
- 'serial-number': self._serial_number,
- 'host': self._host,
- 'olt_serial_number': self._olt_serial_number,
- 'datapath_id': self._datapath_id,
- 'device_id' : self._device_id,
- 'registration_id' : self._reg_id
- }
-
- def clear_alarm(self):
- raise NotImplementedError('ONU Active Alarms are auto-clear')
-
diff --git a/voltha/adapters/adtran_olt/alarms/onu_discovery_alarm.py b/voltha/adapters/adtran_olt/alarms/onu_discovery_alarm.py
deleted file mode 100644
index c9dd527..0000000
--- a/voltha/adapters/adtran_olt/alarms/onu_discovery_alarm.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright 2017-present Adtran, Inc.
-#
-# 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.
-from voltha.protos.events_pb2 import AlarmEventType, AlarmEventSeverity, AlarmEventCategory
-from adapter_alarms import AlarmBase
-
-
-class OnuDiscoveryAlarm(AlarmBase):
- def __init__(self, handler, pon_id, serial_number):
- super(OnuDiscoveryAlarm, self).__init__(handler, 'ONU Discovery',
- alarm='Discovery',
- alarm_category=AlarmEventCategory.PON,
- resource_id=pon_id,
- alarm_type=AlarmEventType.EQUIPMENT,
- alarm_severity=AlarmEventSeverity.CRITICAL)
- self._pon_id = pon_id
- self._serial_number = serial_number
-
- def get_context_data(self):
- return {
- 'pon-id': self._pon_id,
- 'serial-number': self._serial_number
- }
-
- def clear_alarm(self):
- raise NotImplementedError('ONU Discovery Alarms are auto-clear')
diff --git a/voltha/adapters/adtran_olt/alarms/onu_los_alarm.py b/voltha/adapters/adtran_olt/alarms/onu_los_alarm.py
deleted file mode 100644
index fba03a6..0000000
--- a/voltha/adapters/adtran_olt/alarms/onu_los_alarm.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright 2017-present Adtran, Inc.
-#
-# 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.
-from voltha.protos.events_pb2 import AlarmEventType, AlarmEventSeverity, AlarmEventCategory
-from adapter_alarms import AlarmBase
-
-
-class OnuLosAlarm(AlarmBase):
- def __init__(self, handler, onu_id):
- super(OnuLosAlarm, self).__init__(handler, 'onu LOS',
- alarm='LOS',
- alarm_category=AlarmEventCategory.ONT,
- alarm_type=AlarmEventType.COMMUNICATION,
- alarm_severity=AlarmEventSeverity.MAJOR)
- self._onu_id = onu_id
-
- def get_context_data(self):
- return {'onu-id': self._onu_id}
-
diff --git a/voltha/adapters/adtran_olt/download.py b/voltha/adapters/adtran_olt/download.py
index cbd3053..2639bdc 100644
--- a/voltha/adapters/adtran_olt/download.py
+++ b/voltha/adapters/adtran_olt/download.py
@@ -22,6 +22,10 @@
log = structlog.get_logger()
+# TODO: Following two would be good provisionable parameters
+DEFAULT_AUTO_AGE_MINUTES = 10
+DEFAULT_MAX_JOB_RUN_SECONDS = 3600 * 4 # Some OLT files are 250MB+
+
class Download(object):
"""Class to wrap an image download"""
@@ -55,6 +59,9 @@
# Download job info
self._download_job_name = None
+ self._age_out_period = DEFAULT_AUTO_AGE_MINUTES
+ self._max_execution = DEFAULT_MAX_JOB_RUN_SECONDS
+
def __str__(self):
return "ImageDownload: {}".format(self.name)
@@ -64,8 +71,8 @@
Create and start a new image download
:param handler: (AdtranDeviceHandler) Device download is for
- :param done_deferred: (Deferred) deferred to fire on completion
:param request: (ImageDownload) Request
+ :param supported_protocols: (list) download methods allowed (http, tftp, ...)
"""
download = Download(handler, request, supported_protocols)
download._deferred = reactor.callLater(0, download.start_download)
@@ -238,27 +245,37 @@
@property
def download_job_xml(self):
- filepath = os.path.split(self._path)
-
+ # TODO: May want to support notifications
+ # TODO: Not sure about this name for the entity
+ entity = 'main 0'
xml = """
<maintenance-jobs xmlns="http://www.adtran.com/ns/yang/adtran-maintenance-jobs" xmlns:adtn-phys-sw-mnt="http://www.adtran.com/ns/yang/adtran-physical-software-maintenance">
<maintenance-job>
<name>{}</name>
<enabled>true</enabled>
<notify-enabled>false</notify-enabled>
- <no-execution-time-limit/>
+ <maximum-execution-time>{}</maximum-execution-time>
<run-once>true</run-once>
<adtn-phys-sw-mnt:download-software>
+ <adtn-phys-sw-mnt:physical-entity>{}</adtn-phys-sw-mnt:physical-entity>
+ <adtn-phys-sw-mnt:software-name>software</adtn-phys-sw-mnt:software-name>
<adtn-phys-sw-mnt:remote-file>
<adtn-phys-sw-mnt:file-server-profile>{}</adtn-phys-sw-mnt:file-server-profile>
- <adtn-phys-sw-mnt:filepath>{}</adtn-phys-sw-mnt:filepath>
<adtn-phys-sw-mnt:filename>{}</adtn-phys-sw-mnt:filename>
+ """.format(self._download_job_name, self._max_execution, entity,
+ self._server_profile_name, self._name)
+
+ if self._path is not None:
+ xml += """
+ <adtn-phys-sw-mnt:filepath>{}</adtn-phys-sw-mnt:filepath>
+ """.format(self._path)
+
+ xml += """
</adtn-phys-sw-mnt:remote-file>
</adtn-phys-sw-mnt:download-software>
</maintenance-job>
</maintenance-jobs>
- """.format(self._download_job_name, self._server_profile_name,
- filepath[0], filepath[1])
+ """
return xml
@property
@@ -277,25 +294,25 @@
@property
def delete_server_profile_xml(self):
xml = """
- <file-servers operation="delete" xmlns="http://www.adtran.com/ns/yang/adtran-file-servers">
- <profiles>
+ <file-servers xmlns="http://www.adtran.com/ns/yang/adtran-file-servers">
+ <profiles operation="delete">
<profile>
<name>{}</name>
</profile>
</profiles>
</file-servers>
- """.format(self._name)
+ """.format(self._server_profile_name)
return xml
@property
def delete_download_job_xml(self):
xml = """
- <maintenance-jobs operation="delete" xmlns="http://www.adtran.com/ns/yang/adtran-maintenance-jobs">
- <maintenance-job>
+ <maintenance-jobs xmlns="http://www.adtran.com/ns/yang/adtran-maintenance-jobs">
+ <maintenance-job operation="delete">>
<name>{}</name>
</maintenance-job>
</maintenance-jobs>
- """.format(self._name)
+ """.format(self._download_job_name)
return xml
@inlineCallbacks
@@ -352,7 +369,6 @@
self._download_state = ImageDownload.DOWNLOAD_FAILED
# Cleanup NETCONF
-
reactor.callLater(0, self._cleanup_download_job, 20)
reactor.callLater(0, self._cleanup_server_profile, 20)
# TODO: Do we signal any completion due to failure?
@@ -375,7 +391,6 @@
device.admin_state = AdminState.ENABLED
self._handler.adapter_agent.update_device(device)
- @inlineCallbacks
def cancel_download(self, request):
log.info('cancel-sw-download', name=self.name)
@@ -466,7 +481,7 @@
'invalid-software': ImageDownload.DOWNLOAD_FAILED, # successfully downloaded the required software but the software was determined to be invalid
'software-storage-failed': ImageDownload.INSUFFICIENT_SPACE, # successfully downloaded the required software but was unable to successfully stored it to memory
}.get(state.lower(), None)
- log.info('download-state', result=result, state=state, name=self.name)
+ log.info('download-software-state', result=result, state=state, name=self.name)
assert result is not None, 'Invalid state'
return result
@@ -484,6 +499,26 @@
'software-committed': ImageDownload.IMAGE_ACTIVATE, # successfully committed the required software. The job terminated successfully
'commit-software-failed': ImageDownload.IMAGE_INACTIVE, # unsuccessfully attempted to commit the required software revision
}.get(state.lower(), None)
- log.info('download-state', result=result, state=state, name=self.name)
+ log.info('download-activate-state', result=result, state=state, name=self.name)
assert result is not None, 'Invalid state'
- return result
\ No newline at end of file
+ return result
+
+ @staticmethod
+ def clear_all(client):
+ """
+ Remove all file server profiles and download jobs
+ :param client: (ncclient) NETCONF Client to use
+ """
+ from twisted.internet import defer
+ del_fs_xml = """
+ <file-servers xmlns="http://www.adtran.com/ns/yang/adtran-file-servers">
+ <profiles operation="delete"/>
+ </file-servers>
+ """
+ del_job_xml = """
+ <maintenance-jobs operation="delete" xmlns="http://www.adtran.com/ns/yang/adtran-maintenance-jobs"/>
+ """
+ dl = [client.edit_config(del_fs_xml),
+ client.edit_config(del_job_xml)]
+
+ return defer.gatherResults(dl, consumeErrors=True)
diff --git a/voltha/adapters/adtran_olt/flow/evc_map.py b/voltha/adapters/adtran_olt/flow/evc_map.py
index 239113e..9c5cbe3 100644
--- a/voltha/adapters/adtran_olt/flow/evc_map.py
+++ b/voltha/adapters/adtran_olt/flow/evc_map.py
@@ -736,7 +736,7 @@
</evc-maps>
</filter>
"""
- log.info('query', xml=get_xml, regex=regex_)
+ log.debug('query', xml=get_xml, regex=regex_)
def request_failed(results, operation):
log.error('{}-failed'.format(operation), results=results)
diff --git a/voltha/adapters/adtran_olt/net/adtran_netconf.py b/voltha/adapters/adtran_olt/net/adtran_netconf.py
index 07518ea..7c4741a 100644
--- a/voltha/adapters/adtran_olt/net/adtran_netconf.py
+++ b/voltha/adapters/adtran_olt/net/adtran_netconf.py
@@ -302,14 +302,14 @@
config, default_operation,
test_option, error_option)
except Exception as e:
- log.exception('edit_config', e=e)
+ log.exception('edit_config', e=e, config=config, target=target)
raise
returnValue(rpc_reply)
def _do_edit_config(self, target, config, default_operation, test_option, error_option):
"""
- Lock the configuration system
+ Perform actual edit-config operation
"""
try:
log.debug('edit-config', target=target, config=config)
@@ -326,7 +326,7 @@
# To check status, use response.ok (boolean)
except RPCError as e:
- log.exception('do_edit_config', e=e)
+ log.exception('do_edit_config', e=e, config=config, target=target)
raise
return response
diff --git a/voltha/adapters/adtran_olt/onu.py b/voltha/adapters/adtran_olt/onu.py
index 4ec2cb3..2681d00 100644
--- a/voltha/adapters/adtran_olt/onu.py
+++ b/voltha/adapters/adtran_olt/onu.py
@@ -215,9 +215,13 @@
# Must remove any non-printable characters
reg_id = ''.join([i if ord(i) < 127 and ord(i) > 31 else '_' for i in reg_id])
# Generate alarm here for regID
- from alarms.onu_active_alarm import OnuActiveAlarm
+ from voltha.extensions.alarms.onu.onu_active_alarm import OnuActiveAlarm
self.log.info('onu-Active-Alarm', serial_number=self._serial_number_string)
- OnuActiveAlarm(self._olt, self._pon_id, self._serial_number_string, reg_id).raise_alarm()
+ device = self._olt.adapter_agent.get_device(self._olt.device_id)
+
+ OnuActiveAlarm(self._olt.alarms, self._olt.device_id, self._pon_id,
+ self._serial_number_string, reg_id, device.serial_number,
+ ipv4_address=device.ipv4_address).raise_alarm()
@property
def enabled(self):
diff --git a/voltha/adapters/adtran_olt/pki/__init__.py b/voltha/adapters/adtran_olt/pki/__init__.py
deleted file mode 100644
index b0fb0b2..0000000
--- a/voltha/adapters/adtran_olt/pki/__init__.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2017-present Open Networking Foundation
-#
-# 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.
diff --git a/voltha/adapters/adtran_olt/pki/adapter_pm_metrics.py b/voltha/adapters/adtran_olt/pki/adapter_pm_metrics.py
deleted file mode 100644
index 053350e..0000000
--- a/voltha/adapters/adtran_olt/pki/adapter_pm_metrics.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# Copyright 2017-present Adtran, Inc.
-#
-# 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.task import LoopingCall
-from voltha.protos.device_pb2 import PmConfig, PmConfigs, PmGroupConfig
-
-
-class AdapterPmMetrics(object):
- def __init__(self, handler, device, grouped=False, freq_override=False):
- self.log = structlog.get_logger(device_id=device.id)
- self.device = device
- self.id = device.id
- self.handler = handler
- self.name = handler.adapter.name
- self.default_freq = 150
- self.grouped = grouped
- self.freq_override = grouped and freq_override
- self.lc = None
-
- def update(self, pm_config):
- raise NotImplementedError('Your derived class should override this method')
-
- # def enable_pm_collection(self, pm_group, remote):
- # if pm_group == 'Ethernet':
- # self.configure_pm_collection_freq(self.default_freq / 10, remote)
- #
- # def disable_pm_collection(self, pm_group, remote):
- # if pm_group == 'nni':
- # self.configure_pm_collection_freq(0, remote)
-
- def make_proto(self):
- raise NotImplementedError('Your derived class should override this method')
-
- def start_collector(self, callback):
- self.log.info("starting-pm-collection", device_name=self.name,
- device_id=self.device.id)
- prefix = 'voltha.{}.{}'.format(self.name, self.device.id)
-
- if self.lc is None:
- self.lc = LoopingCall(callback, self.device.id, prefix)
-
- self.lc.start(interval=self.default_freq / 10)
-
- def stop_collector(self):
- if self.lc is not None:
- self.lc.stop()
-
- def collect_metrics(self, group, names, config):
- stats = {metric: getattr(group, metric) for (metric, t) in names}
- return {metric: value for metric, value in stats.iteritems()
- if config[metric].enabled}
diff --git a/voltha/adapters/adtran_olt/pki/olt_pm_metrics.py b/voltha/adapters/adtran_olt/pki/olt_pm_metrics.py
deleted file mode 100644
index 2d1fdf6..0000000
--- a/voltha/adapters/adtran_olt/pki/olt_pm_metrics.py
+++ /dev/null
@@ -1,242 +0,0 @@
-# Copyright 2017-present Adtran, Inc.
-#
-# 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 voltha.protos.device_pb2 import PmConfig, PmConfigs, PmGroupConfig
-
-from adapter_pm_metrics import AdapterPmMetrics
-
-
-class OltPmMetrics(AdapterPmMetrics):
- def __init__(self, handler, device, grouped=False, freq_override=False):
- super(OltPmMetrics, self).__init__(handler, device,
- grouped=grouped, freq_override=freq_override)
-
- # PM Config Types are COUNTER, GUAGE, and STATE # GAUGE is misspelled device.proto
- self.nni_pm_names = {
- ('admin_state', PmConfig.STATE),
- ('oper_status', PmConfig.STATE),
- ('port_no', PmConfig.GUAGE), # Device and logical_device port numbers same
- ('rx_packets', PmConfig.COUNTER),
- ('rx_bytes', PmConfig.COUNTER),
- ('rx_dropped', PmConfig.COUNTER),
- ('rx_errors', PmConfig.COUNTER),
- ('rx_bcast', PmConfig.COUNTER),
- ('rx_mcast', PmConfig.COUNTER),
- ('tx_packets', PmConfig.COUNTER),
- ('tx_bytes', PmConfig.COUNTER),
- ('tx_dropped', PmConfig.COUNTER),
- ('tx_bcast', PmConfig.COUNTER),
- ('tx_mcast', PmConfig.COUNTER),
- #
- # Commented out are from spec. May not be supported or implemented yet
- # ('rx_64', PmConfig.COUNTER),
- # ('rx_65_127', PmConfig.COUNTER),
- # ('rx_128_255', PmConfig.COUNTER),
- # ('rx_256_511', PmConfig.COUNTER),
- # ('rx_512_1023', PmConfig.COUNTER),
- # ('rx_1024_1518', PmConfig.COUNTER),
- # ('rx_frame_err', PmConfig.COUNTER),
- # ('rx_over_err', PmConfig.COUNTER),
- # ('rx_crc_err', PmConfig.COUNTER),
- # ('rx_64', PmConfig.COUNTER),
- # ('tx_65_127', PmConfig.COUNTER),
- # ('tx_128_255', PmConfig.COUNTER),
- # ('tx_256_511', PmConfig.COUNTER),
- # ('tx_512_1023', PmConfig.COUNTER),
- # ('tx_1024_1518', PmConfig.COUNTER),
- # ('collisions', PmConfig.COUNTER),
- }
- self.pon_pm_names = {
- ('admin_state', PmConfig.STATE),
- ('oper_status', PmConfig.STATE),
- ('port_no', PmConfig.GUAGE), # Physical device port number
- ('pon_id', PmConfig.GUAGE),
- ('rx_packets', PmConfig.COUNTER),
- ('rx_bytes', PmConfig.COUNTER),
- ('tx_packets', PmConfig.COUNTER),
- ('tx_bytes', PmConfig.COUNTER),
- ('tx_bip_errors', PmConfig.COUNTER),
- ('in_service_onus', PmConfig.GUAGE),
- ('closest_onu_distance', PmConfig.GUAGE)
- }
- self.onu_pm_names = {
- ('pon_id', PmConfig.GUAGE),
- ('onu_id', PmConfig.GUAGE),
- ('fiber_length', PmConfig.GUAGE),
- ('equalization_delay', PmConfig.GUAGE),
- ('rssi', PmConfig.GUAGE), #
- }
- self.gem_pm_names = {
- ('pon_id', PmConfig.GUAGE),
- ('onu_id', PmConfig.GUAGE),
- ('gem_id', PmConfig.GUAGE),
- ('alloc_id', PmConfig.GUAGE),
- ('rx_packets', PmConfig.COUNTER),
- ('rx_bytes', PmConfig.COUNTER),
- ('tx_packets', PmConfig.COUNTER),
- ('tx_bytes', PmConfig.COUNTER),
- }
- self.nni_metrics_config = {m: PmConfig(name=m, type=t, enabled=True)
- for (m, t) in self.nni_pm_names}
- self.pon_metrics_config = {m: PmConfig(name=m, type=t, enabled=True)
- for (m, t) in self.pon_pm_names}
- self.onu_metrics_config = {m: PmConfig(name=m, type=t, enabled=True)
- for (m, t) in self.onu_pm_names}
- self.gem_metrics_config = {m: PmConfig(name=m, type=t, enabled=True)
- for (m, t) in self.gem_pm_names}
-
- def update(self, pm_config):
- # TODO: Test both 'group' and 'non-group' functionality
- # TODO: Test frequency override capability for a particular group
- if self.default_freq != pm_config.default_freq:
- # Update the callback to the new frequency.
- self.default_freq = pm_config.default_freq
- self.lc.stop()
- self.lc.start(interval=self.default_freq / 10)
-
- if pm_config.grouped is True:
- for m in pm_config.groups:
- pass
- # self.pm_group_metrics[m.group_name].config.enabled = m.enabled
- # if m.enabled is True:
- # self.enable_pm_collection(m.group_name, remote)
- # else:
- # self.disable_pm_collection(m.group_name, remote)
- else:
- for m in pm_config.metrics:
- self.nni_metrics_config[m.name].enabled = m.enabled
- self.pon_metrics_config[m.name].enabled = m.enabled
- self.onu_metrics_config[m.name].enabled = m.enabled
- self.gem_metrics_config[m.name].enabled = m.enabled
-
- def make_proto(self):
- pm_config = PmConfigs(id=self.id, default_freq=self.default_freq,
- grouped=self.grouped,
- freq_override=self.freq_override)
- metrics = set()
-
- if self.grouped:
- pm_ether_stats = PmGroupConfig(group_name='Ethernet',
- group_freq=self.default_freq,
- enabled=True)
-
- pm_pon_stats = PmGroupConfig(group_name='PON',
- group_freq=self.default_freq,
- enabled=True)
-
- pm_ont_stats = PmGroupConfig(group_name='ONT',
- group_freq=self.default_freq,
- enabled=True)
-
- pm_gem_stats = PmGroupConfig(group_name='GEM',
- group_freq=self.default_freq,
- enabled=True)
- else:
- pm_ether_stats = pm_config
- pm_pon_stats = pm_config
- pm_ont_stats = pm_config
- pm_gem_stats = pm_config
-
- for m in sorted(self.nni_metrics_config):
- pm = self.nni_metrics_config[m]
- if not self.grouped:
- if pm.name in metrics:
- continue
- metrics.add(pm.name)
- pm_ether_stats.metrics.extend([PmConfig(name=pm.name,
- type=pm.type,
- enabled=pm.enabled)])
-
- for m in sorted(self.pon_metrics_config):
- pm = self.pon_metrics_config[m]
- if not self.grouped:
- if pm.name in metrics:
- continue
- metrics.add(pm.name)
- pm_pon_stats.metrics.extend([PmConfig(name=pm.name,
- type=pm.type,
- enabled=pm.enabled)])
-
- for m in sorted(self.onu_metrics_config):
- pm = self.onu_metrics_config[m]
- if not self.grouped:
- if pm.name in metrics:
- continue
- metrics.add(pm.name)
- pm_ont_stats.metrics.extend([PmConfig(name=pm.name,
- type=pm.type,
- enabled=pm.enabled)])
-
- for m in sorted(self.gem_metrics_config):
- pm = self.gem_metrics_config[m]
- if not self.grouped:
- if pm.name in metrics:
- continue
- metrics.add(pm.name)
- pm_gem_stats.metrics.extend([PmConfig(name=pm.name,
- type=pm.type,
- enabled=pm.enabled)])
- if self.grouped:
- pm_config.groups.extend([pm_ether_stats,
- pm_pon_stats,
- pm_ont_stats,
- pm_gem_stats])
- return pm_config
-
- def collect_port_metrics(self):
- port_metrics = dict()
-
- for port in self.handler.northbound_ports.itervalues():
- port_metrics['nni.{}'.format(port.port_no)] = self.collect_nni_metrics(port)
-
- for port in self.handler.southbound_ports.itervalues():
- port_metrics['pon.{}'.format(port.pon_id)] = self.collect_pon_metrics(port)
-
- for onu_id in port.onu_ids:
- onu = port.onu(onu_id)
- if onu is not None:
- port_metrics['pon.{}.onu.{}'.format(port.pon_id, onu.onu_id)] = \
- self.collect_onu_metrics(onu)
- for gem in onu.gem_ports:
- if gem.multicast:
- continue
-
- port_metrics['pon.{}.onu.{}.gem.{}'.format(port.pon_id,
- onu.onu_id,
- gem.gem_id)] = \
- self.collect_gem_metrics(gem)
- # TODO: Do any multicast GEM PORT metrics here...
- return port_metrics
-
- def collect_nni_metrics(self, nni_port):
- stats = {metric: getattr(nni_port, metric) for (metric, t) in self.nni_pm_names}
- return {metric: value for metric, value in stats.iteritems()
- if self.nni_metrics_config[metric].enabled}
-
- def collect_pon_metrics(self, pon_port):
- stats = {metric: getattr(pon_port, metric) for (metric, t) in self.pon_pm_names}
- return {metric: value for metric, value in stats.iteritems()
- if self.pon_metrics_config[metric].enabled}
-
- def collect_onu_metrics(self, onu):
- stats = {metric: getattr(onu, metric) for (metric, t) in self.onu_pm_names}
- return {metric: value for metric, value in stats.iteritems()
- if self.onu_metrics_config[metric].enabled}
-
- def collect_gem_metrics(self, gem):
- stats = {metric: getattr(gem, metric) for (metric, t) in self.gem_pm_names}
- return {metric: value for metric, value in stats.iteritems()
- if self.gem_metrics_config[metric].enabled}
diff --git a/voltha/adapters/adtran_olt/pon_port.py b/voltha/adapters/adtran_olt/pon_port.py
index d0281ca..82dcd9b 100644
--- a/voltha/adapters/adtran_olt/pon_port.py
+++ b/voltha/adapters/adtran_olt/pon_port.py
@@ -18,20 +18,20 @@
import structlog
from port import AdtnPort
from twisted.internet import reactor, defer
-from twisted.internet.defer import inlineCallbacks, returnValue, succeed
+from twisted.internet.defer import inlineCallbacks, returnValue
from adtran_olt_handler import AdtranOltHandler
from net.adtran_rest import RestInvalidResponseCode
from codec.olt_config import OltConfig
from onu import Onu
-from alarms.onu_los_alarm import OnuLosAlarm
+from voltha.extensions.alarms.onu.onu_los_alarm import OnuLosAlarm
from voltha.protos.common_pb2 import AdminState
from voltha.protos.device_pb2 import Port
try:
- from alarms.onu_discovery_alarm2 import OnuDiscoveryAlarm
+ from voltha.extensions.alarms.onu.onu_discovery_alarm import OnuDiscoveryAlarm
except ImportError:
- from alarms.onu_discovery_alarm import OnuDiscoveryAlarm
+ from voltha.extensions.alarms.onu.onu_discovery_alarm import OnuDiscoveryAlarm
class PonPort(AdtnPort):
@@ -736,11 +736,11 @@
for onu_id in cleared_alarms:
self._active_los_alarms.remove(onu_id)
- OnuLosAlarm(self.olt, onu_id).clear_alarm()
+ OnuLosAlarm(self.olt.alarms, onu_id).clear_alarm()
for onu_id in new_alarms:
self._active_los_alarms.add(onu_id)
- OnuLosAlarm(self.olt, onu_id).raise_alarm()
+ OnuLosAlarm(self.olt.alarms, onu_id).raise_alarm()
self.delete_onu(onu_id)
def _process_status_onu_discovered_list(self, discovered_onus):
@@ -851,8 +851,9 @@
onu_info = self._get_onu_info(serial_number)
if onu_info is None:
- self.log.info('onu-lookup-failure', serial_number=serial_number_64)
- OnuDiscoveryAlarm(self.olt, self.pon_id, serial_number).raise_alarm()
+ self.log.info('onu-lookup-failure', serial_number=serial_number,
+ serial_number_64=serial_number_64)
+ OnuDiscoveryAlarm(self.olt.alarms, self.pon_id, serial_number).raise_alarm()
returnValue('new-onu')
if serial_number_64 not in status.onus or onu_info['onu-id'] in self._active_los_alarms:
@@ -866,7 +867,7 @@
elif (serial_number_64 in self._onus and onu_id not in self._onu_by_id) or \
(serial_number_64 not in self._onus and onu_id in self._onu_by_id):
# May be here due to unmanaged power-cycle on OLT or fiber bounced for a
- # previously activated ONU. Drop it and add bac on next discovery cycle
+ # previously activated ONU. Drop it and add back on next discovery cycle
self.delete_onu(onu_id)
elif len(self._onus) >= self.MAX_ONUS_SUPPORTED:
diff --git a/voltha/adapters/adtran_olt/port.py b/voltha/adapters/adtran_olt/port.py
index 5a0a025..69597a7 100644
--- a/voltha/adapters/adtran_olt/port.py
+++ b/voltha/adapters/adtran_olt/port.py
@@ -12,21 +12,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import json
-import random
-
import structlog
from enum import Enum
-from twisted.internet import reactor, defer
+from twisted.internet import reactor
from twisted.internet.defer import inlineCallbacks, returnValue, succeed
-from adtran_olt_handler import AdtranOltHandler
-from net.adtran_rest import RestInvalidResponseCode
-from codec.olt_config import OltConfig
-from onu import Onu
-from alarms.onu_los_alarm import OnuLosAlarm
from voltha.protos.common_pb2 import OperStatus, AdminState
-from voltha.protos.device_pb2 import Port
class AdtnPort(object):