Coverage for watcher/decision_engine/datasources/monasca.py: 81%
70 statements
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-17 12:22 +0000
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-17 12:22 +0000
1# -*- encoding: utf-8 -*-
2# Copyright (c) 2016 b<>com
3#
4# Authors: Vincent FRANCOISE <vincent.francoise@b-com.com>
5#
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15# implied.
16# See the License for the specific language governing permissions and
17# limitations under the License.
19import datetime
21from monascaclient import exc
22from oslo_utils import timeutils
24from watcher.common import clients
25from watcher.decision_engine.datasources import base
28class MonascaHelper(base.DataSourceBase):
30 NAME = 'monasca'
31 METRIC_MAP = dict(host_cpu_usage='cpu.percent',
32 host_ram_usage=None,
33 host_outlet_temp=None,
34 host_inlet_temp=None,
35 host_airflow=None,
36 host_power=None,
37 instance_cpu_usage='vm.cpu.utilization_perc',
38 instance_ram_usage=None,
39 instance_ram_allocated=None,
40 instance_l3_cache_usage=None,
41 instance_root_disk_size=None,
42 )
44 def __init__(self, osc=None):
45 """:param osc: an OpenStackClients instance"""
46 self.osc = osc if osc else clients.OpenStackClients()
47 self.monasca = self.osc.monasca()
49 def _format_time_params(self, start_time, end_time, period):
50 """Format time-related params to the correct Monasca format
52 :param start_time: Start datetime from which metrics will be used
53 :param end_time: End datetime from which metrics will be used
54 :param period: interval in seconds (int)
55 :return: start ISO time, end ISO time, period
56 """
58 if not period:
59 period = int(datetime.timedelta(hours=3).total_seconds())
60 if not start_time:
61 start_time = (
62 timeutils.utcnow() - datetime.timedelta(seconds=period))
64 start_timestamp = None if not start_time else start_time.isoformat()
65 end_timestamp = None if not end_time else end_time.isoformat()
67 return start_timestamp, end_timestamp, period
69 def query_retry_reset(self, exception_instance):
70 if isinstance(exception_instance, exc.Unauthorized): 70 ↛ 71line 70 didn't jump to line 71 because the condition on line 70 was never true
71 self.osc.reset_clients()
72 self.monasca = self.osc.monasca()
74 def check_availability(self):
75 result = self.query_retry(self.monasca.metrics.list)
76 if result:
77 return 'available'
78 else:
79 return 'not available'
81 def list_metrics(self):
82 # TODO(alexchadin): this method should be implemented in accordance to
83 # monasca API.
84 pass
86 def statistic_aggregation(self, resource=None, resource_type=None,
87 meter_name=None, period=300, aggregate='mean',
88 granularity=300):
89 stop_time = timeutils.utcnow()
90 start_time = stop_time - datetime.timedelta(seconds=(int(period)))
92 meter = self._get_meter(meter_name)
94 if aggregate == 'mean': 94 ↛ 97line 94 didn't jump to line 97 because the condition on line 94 was always true
95 aggregate = 'avg'
97 raw_kwargs = dict(
98 name=meter,
99 start_time=start_time.isoformat(),
100 end_time=stop_time.isoformat(),
101 dimensions={'hostname': resource.uuid},
102 period=period,
103 statistics=aggregate,
104 group_by='*',
105 )
107 kwargs = {k: v for k, v in raw_kwargs.items() if k and v}
109 statistics = self.query_retry(
110 f=self.monasca.metrics.list_statistics, **kwargs)
112 cpu_usage = None
113 for stat in statistics:
114 avg_col_idx = stat['columns'].index(aggregate)
115 values = [r[avg_col_idx] for r in stat['statistics']]
116 value = float(sum(values)) / len(values)
117 cpu_usage = value
119 return cpu_usage
121 def statistic_series(self, resource=None, resource_type=None,
122 meter_name=None, start_time=None, end_time=None,
123 granularity=300):
125 meter = self._get_meter(meter_name)
127 raw_kwargs = dict(
128 name=meter,
129 start_time=start_time.isoformat(),
130 end_time=end_time.isoformat(),
131 dimensions={'hostname': resource.uuid},
132 statistics='avg',
133 group_by='*',
134 )
136 kwargs = {k: v for k, v in raw_kwargs.items() if k and v}
138 statistics = self.query_retry(
139 f=self.monasca.metrics.list_statistics, **kwargs)
141 result = {}
142 for stat in statistics:
143 v_index = stat['columns'].index('avg')
144 t_index = stat['columns'].index('timestamp')
145 result.update({r[t_index]: r[v_index] for r in stat['statistics']})
147 return result
149 def get_host_cpu_usage(self, resource, period,
150 aggregate, granularity=None):
151 return self.statistic_aggregation(
152 resource, 'compute_node', 'host_cpu_usage', period, aggregate,
153 granularity)
155 def get_host_ram_usage(self, resource, period,
156 aggregate, granularity=None):
157 raise NotImplementedError
159 def get_host_outlet_temp(self, resource, period,
160 aggregate, granularity=None):
161 raise NotImplementedError
163 def get_host_inlet_temp(self, resource, period,
164 aggregate, granularity=None):
165 raise NotImplementedError
167 def get_host_airflow(self, resource, period,
168 aggregate, granularity=None):
169 raise NotImplementedError
171 def get_host_power(self, resource, period,
172 aggregate, granularity=None):
173 raise NotImplementedError
175 def get_instance_cpu_usage(self, resource, period,
176 aggregate, granularity=None):
178 return self.statistic_aggregation(
179 resource, 'instance', 'instance_cpu_usage', period, aggregate,
180 granularity)
182 def get_instance_ram_usage(self, resource, period,
183 aggregate, granularity=None):
184 raise NotImplementedError
186 def get_instance_ram_allocated(self, resource, period,
187 aggregate, granularity=None):
188 raise NotImplementedError
190 def get_instance_l3_cache_usage(self, resource, period,
191 aggregate, granularity=None):
192 raise NotImplementedError
194 def get_instance_root_disk_size(self, resource, period,
195 aggregate, granularity=None):
196 raise NotImplementedError