blob: e3671f5d8331ace4eeb19c6131b492ce551d7316 [file] [log] [blame]
Chip Boling67b674a2019-02-08 11:42:18 -06001# Copyright 2017-present Open Networking Foundation
2#
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
Zack Williams84a71e92019-11-15 09:00:19 -070015from __future__ import absolute_import, division
William Kurkianede82e92019-03-05 13:02:57 -050016from voltha_protos.device_pb2 import PmConfig, PmConfigs, PmGroupConfig
Devmalya Paul0d3abf02019-07-31 18:34:27 -040017from pyvoltha.adapters.extensions.events.kpi.adapter_pm_metrics import AdapterPmMetrics
18from pyvoltha.adapters.extensions.events.kpi.onu.onu_omci_pm import OnuOmciPmMetrics
Chip Boling67b674a2019-02-08 11:42:18 -060019
20
21class OnuPmMetrics(AdapterPmMetrics):
22 """
23 Shared ONU Device Adapter PM Metrics Manager
24
25 This class specifically addresses ONU general PM (health, ...) area
26 specific PM (OMCI, PON, UNI) is supported in encapsulated classes accessible
27 from this object
28 """
29
30 # Metric default settings
31 DEFAULT_HEARTBEAT_ENABLED = False
32 DEFAULT_HEARTBEAT_FREQUENCY = 1200 # 1/10ths of a second
33 #
34 # Currently only a single KPI metrics collection occurs (individual group
35 # frequency not supported). The next value defines this single frequency until
36 # the KPI shared library supports individual collection.
37 DEFAULT_ONU_COLLECTION_FREQUENCY = 60 * 10 # 1 minute
38
Devmalya Paul0d3abf02019-07-31 18:34:27 -040039 def __init__(self, event_mgr, core_proxy, device_id, logical_device_id, serial_number,
Chip Boling67b674a2019-02-08 11:42:18 -060040 grouped=False, freq_override=False, **kwargs):
41 """
42 Initializer for shared ONU Device Adapter PM metrics
43
William Kurkian6eda8182019-05-03 15:51:54 -040044 :param core_proxy: (CoreProxy) Core proxy for the device
Chip Boling67b674a2019-02-08 11:42:18 -060045 :param device_id: (str) Device ID
46 :param logical_device_id: (str) VOLTHA Logical Device ID
47 :param grouped: (bool) Flag indicating if statistics are managed as a group
48 :param freq_override: (bool) Flag indicating if frequency collection can be specified
49 on a per group basis
50 :param kwargs: (dict) Device Adapter specific values. For an ONU Device adapter, the
51 expected key-value pairs are listed below. If not provided, the
52 associated PMv statistics are not gathered:
53
54 'heartbeat': Reference to the a class that provides an ONU heartbeat
55 statistics. TODO: This should be standardized across adapters
56 """
Devmalya Paul0d3abf02019-07-31 18:34:27 -040057 super(OnuPmMetrics, self).__init__(event_mgr, core_proxy, device_id, logical_device_id, serial_number,
Chip Boling67b674a2019-02-08 11:42:18 -060058 grouped=grouped, freq_override=freq_override,
59 **kwargs)
60
61 # The following HeartBeat PM is only an example. We may want to have a common heartbeat
62 # object for OLT and ONU DAs that work the same. If so, it could also provide PM information
63 #
64 # TODO: In the actual 'collection' of PM data, I have the heartbeat stats disabled since
65 # there is not yet a common 'heartbeat' object
66 #
67 self.health_pm_names = {
68 ('alarm_active', PmConfig.STATE),
69 ('heartbeat_count', PmConfig.COUNTER),
70 ('heartbeat_miss', PmConfig.COUNTER),
71 ('alarms_raised_count', PmConfig.COUNTER),
72 ('heartbeat_failed_limit', PmConfig.COUNTER),
73 ('heartbeat_interval', PmConfig.COUNTER),
74 }
75 # TODO Add PON Port pollable PM as a separate class and include like OMCI
76 # TODO Add UNI Port pollable PM as a separate class and include like OMCI
77 self._heartbeat = kwargs.pop('heartbeat', None)
78 self.health_metrics_config = {m: PmConfig(name=m, type=t, enabled=True)
79 for (m, t) in self.health_pm_names}
80
Devmalya Paul0d3abf02019-07-31 18:34:27 -040081 self.omci_pm = OnuOmciPmMetrics(event_mgr, core_proxy, device_id, logical_device_id, serial_number,
Chip Boling67b674a2019-02-08 11:42:18 -060082 grouped=grouped, freq_override=freq_override,
83 **kwargs)
84
85 def update(self, pm_config):
86 try:
87 # TODO: Test frequency override capability for a particular group
88 if self.default_freq != pm_config.default_freq:
89 # Update the callback to the new frequency.
90 self.default_freq = pm_config.default_freq
Rohan Agrawal9a028682020-06-01 09:08:14 +000091 self.stop_collector()
92 self.start_collector()
Chip Boling67b674a2019-02-08 11:42:18 -060093
Rohan Agrawal01092e92020-06-29 10:59:59 +000094 if self.max_skew != pm_config.max_skew:
95 self.max_skew = pm_config.max_skew
96
Chip Boling67b674a2019-02-08 11:42:18 -060097 if pm_config.grouped:
98 for group in pm_config.groups:
99 group_config = self.pm_group_metrics.get(group.group_name)
100 if group_config is not None:
101 group_config.enabled = group.enabled
Rohan Agrawal01092e92020-06-29 10:59:59 +0000102
Chip Boling67b674a2019-02-08 11:42:18 -0600103 else:
104 msg = 'There are no independent ONU metrics, only group metrics at this time'
105 raise NotImplemented(msg)
106
107 except Exception as e:
108 self.log.exception('update-failure', e=e)
109 raise
110
111 self.omci_pm.update(pm_config)
112
113 def make_proto(self, pm_config=None):
114 if pm_config is None:
115 pm_config = PmConfigs(id=self.device_id,
116 default_freq=self.default_freq,
117 grouped=self.grouped,
Rohan Agrawal01092e92020-06-29 10:59:59 +0000118 freq_override=self.freq_override,
119 max_skew=self.max_skew)
Chip Boling67b674a2019-02-08 11:42:18 -0600120 metrics = set()
121
122 if self._heartbeat is not None:
123 if self.grouped:
124 pm_health_stats = PmGroupConfig(group_name='Heartbeat',
125 group_freq=OnuPmMetrics.DEFAULT_HEARTBEAT_FREQUENCY,
126 enabled=OnuPmMetrics.DEFAULT_HEARTBEAT_ENABLED)
127 self.pm_group_metrics[pm_health_stats.group_name] = pm_health_stats
128 else:
129 pm_health_stats = pm_config
130
131 # Add metrics to the PM Group (or as individual metrics_
132 for m in sorted(self.health_metrics_config):
133 pm = self.health_metrics_config[m]
134 if not self.grouped:
135 if pm.name in metrics:
136 continue
137 metrics.add(pm.name)
138
139 pm_health_stats.metrics.extend([PmConfig(name=pm.name,
140 type=pm.type,
141 enabled=pm.enabled)])
142 if self.grouped:
143 pm_config.groups.extend([pm_health_stats])
144
145 # TODO Add PON Port PM
146 # TODO Add UNI Port PM
147 pm_config = self.omci_pm.make_proto(pm_config)
148 return pm_config
149
150 def collect_metrics(self, data=None):
151 """
152 Collect metrics for this adapter.
153
154 The data collected (or passed in) is a list of pairs/tuples. Each
155 pair is composed of a MetricMetaData metadata-portion and list of MetricValuePairs
156 that contains a single individual metric or list of metrics if this is a
157 group metric.
158
159 This method is called for each adapter at a fixed frequency.
160 TODO: Currently all group metrics are collected on a single timer tick.
161 This needs to be fixed as independent group or instance collection is
162 desirable.
163
164 :param data: (list) Existing list of collected metrics (MetricInformation).
165 This is provided to allow derived classes to call into
166 further encapsulated classes.
167
168 :return: (list) metadata and metrics pairs - see description above
169 """
170 if data is None:
171 data = list()
172
173 # TODO: Heartbeat stats disabled since it is not a common item on all ONUs (or OLTs)
174 # if self._heartbeat is not None:
175 # data.extend(self.collect_metrics(self._heartbeat, self.health_pm_names,
176 # self.health_metrics_config))
177 return self.omci_pm.collect_metrics(data=data)