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