Coverage for watcher/decision_engine/solution/efficacy.py: 89%

40 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# Licensed under the Apache License, Version 2.0 (the "License"); 

5# you may not use this file except in compliance with the License. 

6# You may obtain a copy of the License at 

7# 

8# http://www.apache.org/licenses/LICENSE-2.0 

9# 

10# Unless required by applicable law or agreed to in writing, software 

11# distributed under the License is distributed on an "AS IS" BASIS, 

12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 

13# implied. 

14# See the License for the specific language governing permissions and 

15# limitations under the License. 

16 

17import numbers 

18 

19from oslo_log import log 

20 

21from watcher._i18n import _ 

22from watcher.common import exception 

23from watcher.common import utils 

24 

25LOG = log.getLogger(__name__) 

26 

27 

28class IndicatorsMap(utils.Struct): 

29 pass 

30 

31 

32class Indicator(utils.Struct): 

33 

34 def __init__(self, name, description, unit, value): 

35 super(Indicator, self).__init__() 

36 self.name = name 

37 self.description = description 

38 self.unit = unit 

39 if not isinstance(value, numbers.Number): 39 ↛ 40line 39 didn't jump to line 40 because the condition on line 39 was never true

40 raise exception.InvalidIndicatorValue( 

41 _("An indicator value should be a number")) 

42 self.value = value 

43 

44 

45class Efficacy(object): 

46 """Solution efficacy""" 

47 

48 def __init__(self, goal, strategy): 

49 """Solution efficacy 

50 

51 :param goal: Goal associated to this solution 

52 :type goal: :py:class:`~.base.Goal` instance 

53 :param strategy: Strategy associated to this solution 

54 :type strategy: :py:class:`~.BaseStrategy` instance 

55 """ 

56 self.goal = goal 

57 self.strategy = strategy 

58 

59 self._efficacy_spec = self.goal.efficacy_specification 

60 

61 # Used to store in DB the info related to the efficacy indicators 

62 self.indicators = [] 

63 # Used to compute the global efficacy 

64 self._indicators_mapping = IndicatorsMap() 

65 self.global_efficacy = [] 

66 

67 def set_efficacy_indicators(self, **indicators_map): 

68 """Set the efficacy indicators 

69 

70 :param indicators_map: kwargs where the key is the name of the efficacy 

71 indicator as defined in the associated 

72 :py:class:`~.IndicatorSpecification` and the 

73 value is a number. 

74 :type indicators_map: dict {str: numerical value} 

75 """ 

76 self._indicators_mapping.update(indicators_map) 

77 

78 def compute_global_efficacy(self): 

79 self._efficacy_spec.validate_efficacy_indicators( 

80 self._indicators_mapping) 

81 try: 

82 self.global_efficacy = ( 

83 self._efficacy_spec.get_global_efficacy_indicator( 

84 self._indicators_mapping)) 

85 

86 indicators_specs_map = { 

87 indicator_spec.name: indicator_spec 

88 for indicator_spec in self._efficacy_spec.indicators_specs} 

89 

90 indicators = [] 

91 for indicator_name, value in self._indicators_mapping.items(): 

92 related_indicator_spec = indicators_specs_map[indicator_name] 

93 indicators.append( 

94 Indicator( 

95 name=related_indicator_spec.name, 

96 description=related_indicator_spec.description, 

97 unit=related_indicator_spec.unit, 

98 value=value)) 

99 

100 self.indicators = indicators 

101 except Exception as exc: 

102 LOG.exception(exc) 

103 raise exception.GlobalEfficacyComputationError( 

104 goal=self.goal.name, 

105 strategy=self.strategy.name)