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

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. 

18 

19import datetime 

20 

21from monascaclient import exc 

22from oslo_utils import timeutils 

23 

24from watcher.common import clients 

25from watcher.decision_engine.datasources import base 

26 

27 

28class MonascaHelper(base.DataSourceBase): 

29 

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 ) 

43 

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() 

48 

49 def _format_time_params(self, start_time, end_time, period): 

50 """Format time-related params to the correct Monasca format 

51 

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 """ 

57 

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)) 

63 

64 start_timestamp = None if not start_time else start_time.isoformat() 

65 end_timestamp = None if not end_time else end_time.isoformat() 

66 

67 return start_timestamp, end_timestamp, period 

68 

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() 

73 

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' 

80 

81 def list_metrics(self): 

82 # TODO(alexchadin): this method should be implemented in accordance to 

83 # monasca API. 

84 pass 

85 

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))) 

91 

92 meter = self._get_meter(meter_name) 

93 

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' 

96 

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 ) 

106 

107 kwargs = {k: v for k, v in raw_kwargs.items() if k and v} 

108 

109 statistics = self.query_retry( 

110 f=self.monasca.metrics.list_statistics, **kwargs) 

111 

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 

118 

119 return cpu_usage 

120 

121 def statistic_series(self, resource=None, resource_type=None, 

122 meter_name=None, start_time=None, end_time=None, 

123 granularity=300): 

124 

125 meter = self._get_meter(meter_name) 

126 

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 ) 

135 

136 kwargs = {k: v for k, v in raw_kwargs.items() if k and v} 

137 

138 statistics = self.query_retry( 

139 f=self.monasca.metrics.list_statistics, **kwargs) 

140 

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']}) 

146 

147 return result 

148 

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) 

154 

155 def get_host_ram_usage(self, resource, period, 

156 aggregate, granularity=None): 

157 raise NotImplementedError 

158 

159 def get_host_outlet_temp(self, resource, period, 

160 aggregate, granularity=None): 

161 raise NotImplementedError 

162 

163 def get_host_inlet_temp(self, resource, period, 

164 aggregate, granularity=None): 

165 raise NotImplementedError 

166 

167 def get_host_airflow(self, resource, period, 

168 aggregate, granularity=None): 

169 raise NotImplementedError 

170 

171 def get_host_power(self, resource, period, 

172 aggregate, granularity=None): 

173 raise NotImplementedError 

174 

175 def get_instance_cpu_usage(self, resource, period, 

176 aggregate, granularity=None): 

177 

178 return self.statistic_aggregation( 

179 resource, 'instance', 'instance_cpu_usage', period, aggregate, 

180 granularity) 

181 

182 def get_instance_ram_usage(self, resource, period, 

183 aggregate, granularity=None): 

184 raise NotImplementedError 

185 

186 def get_instance_ram_allocated(self, resource, period, 

187 aggregate, granularity=None): 

188 raise NotImplementedError 

189 

190 def get_instance_l3_cache_usage(self, resource, period, 

191 aggregate, granularity=None): 

192 raise NotImplementedError 

193 

194 def get_instance_root_disk_size(self, resource, period, 

195 aggregate, granularity=None): 

196 raise NotImplementedError