Coverage for watcher/decision_engine/strategy/strategies/dummy_with_scorer.py: 97%

67 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 Intel 

3# 

4# Authors: Tomasz Kaczynski <tomasz.kaczynski@intel.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# 

19 

20import random 

21 

22from oslo_log import log 

23from oslo_serialization import jsonutils 

24from oslo_utils import units 

25 

26from watcher._i18n import _ 

27from watcher.decision_engine.scoring import scoring_factory 

28from watcher.decision_engine.strategy.strategies import base 

29 

30LOG = log.getLogger(__name__) 

31 

32 

33class DummyWithScorer(base.DummyBaseStrategy): 

34 """A dummy strategy using dummy scoring engines. 

35 

36 This is a dummy strategy demonstrating how to work with scoring 

37 engines. One scoring engine is predicting the workload type of a machine 

38 based on the telemetry data, the other one is simply calculating the 

39 average value for given elements in a list. Results are then passed to the 

40 NOP action. 

41 

42 The strategy is presenting the whole workflow: 

43 - Get a reference to a scoring engine 

44 - Prepare input data (features) for score calculation 

45 - Perform score calculation 

46 - Use scorer's metadata for results interpretation 

47 """ 

48 

49 DEFAULT_NAME = "dummy_with_scorer" 

50 DEFAULT_DESCRIPTION = "Dummy Strategy with Scorer" 

51 

52 NOP = "nop" 

53 SLEEP = "sleep" 

54 

55 def __init__(self, config, osc=None): 

56 """Constructor: the signature should be identical within the subclasses 

57 

58 :param config: Configuration related to this plugin 

59 :type config: :py:class:`~.Struct` 

60 :param osc: An OpenStackClients instance 

61 :type osc: :py:class:`~.OpenStackClients` instance 

62 """ 

63 

64 super(DummyWithScorer, self).__init__(config, osc) 

65 

66 # Setup Scoring Engines 

67 self._workload_scorer = (scoring_factory 

68 .get_scoring_engine('dummy_scorer')) 

69 self._avg_scorer = (scoring_factory 

70 .get_scoring_engine('dummy_avg_scorer')) 

71 

72 # Get metainfo from Workload Scorer for result interpretation 

73 metainfo = jsonutils.loads(self._workload_scorer.get_metainfo()) 

74 self._workloads = {index: workload 

75 for index, workload in enumerate( 

76 metainfo['workloads'])} 

77 

78 def pre_execute(self): 

79 self._pre_execute() 

80 

81 def do_execute(self, audit=None): 

82 # Simple "hello world" from strategy 

83 param1 = self.input_parameters.param1 

84 param2 = self.input_parameters.param2 

85 LOG.debug('DummyWithScorer params: param1=%(p1)f, param2=%(p2)s', 

86 {'p1': param1, 'p2': param2}) 

87 parameters = {'message': 'Hello from Dummy Strategy with Scorer!'} 

88 self.solution.add_action(action_type=self.NOP, 

89 input_parameters=parameters) 

90 

91 # Demonstrate workload scorer 

92 features = self._generate_random_telemetry() 

93 result_str = self._workload_scorer.calculate_score(features) 

94 LOG.debug('Workload Scorer result: %s', result_str) 

95 

96 # Parse the result using workloads from scorer's metainfo 

97 result = self._workloads[jsonutils.loads(result_str)[0]] 

98 LOG.debug('Detected Workload: %s', result) 

99 parameters = {'message': 'Detected Workload: %s' % result} 

100 self.solution.add_action(action_type=self.NOP, 

101 input_parameters=parameters) 

102 

103 # Demonstrate AVG scorer 

104 features = jsonutils.dumps(random.sample(range(1000), 20)) 

105 result_str = self._avg_scorer.calculate_score(features) 

106 LOG.debug('AVG Scorer result: %s', result_str) 

107 result = jsonutils.loads(result_str)[0] 

108 LOG.debug('AVG Scorer result (parsed): %d', result) 

109 parameters = {'message': 'AVG Scorer result: %s' % result} 

110 self.solution.add_action(action_type=self.NOP, 

111 input_parameters=parameters) 

112 

113 # Sleep action 

114 self.solution.add_action(action_type=self.SLEEP, 

115 input_parameters={'duration': 5.0}) 

116 

117 def post_execute(self): 

118 pass 

119 

120 @classmethod 

121 def get_name(cls): 

122 return 'dummy_with_scorer' 

123 

124 @classmethod 

125 def get_display_name(cls): 

126 return _('Dummy Strategy using sample Scoring Engines') 

127 

128 @classmethod 

129 def get_translatable_display_name(cls): 

130 return 'Dummy Strategy using sample Scoring Engines' 

131 

132 @classmethod 

133 def get_schema(cls): 

134 # Mandatory default setting for each element 

135 return { 

136 'properties': { 

137 'param1': { 

138 'description': 'number parameter example', 

139 'type': 'number', 

140 'default': 3.2, 

141 'minimum': 1.0, 

142 'maximum': 10.2, 

143 }, 

144 'param2': { 

145 'description': 'string parameter example', 

146 'type': "string", 

147 'default': "hello" 

148 }, 

149 }, 

150 } 

151 

152 def _generate_random_telemetry(self): 

153 processor_time = random.randint(0, 100) 

154 mem_total_bytes = 4*units.Gi 

155 mem_avail_bytes = random.randint(1*units.Gi, 4*units.Gi) 

156 mem_page_reads = random.randint(0, 2000) 

157 mem_page_writes = random.randint(0, 2000) 

158 disk_read_bytes = random.randint(0*units.Mi, 200*units.Mi) 

159 disk_write_bytes = random.randint(0*units.Mi, 200*units.Mi) 

160 net_bytes_received = random.randint(0*units.Mi, 20*units.Mi) 

161 net_bytes_sent = random.randint(0*units.Mi, 10*units.Mi) 

162 

163 return jsonutils.dumps([ 

164 processor_time, mem_total_bytes, mem_avail_bytes, 

165 mem_page_reads, mem_page_writes, disk_read_bytes, 

166 disk_write_bytes, net_bytes_received, net_bytes_sent])