Coverage for manila/scheduler/weighers/goodness.py: 98%
46 statements
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
1# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# 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, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
16from oslo_log import log as logging
18from manila.scheduler.evaluator import evaluator
19from manila.scheduler import utils
20from manila.scheduler.weighers import base_host
23LOG = logging.getLogger(__name__)
26class GoodnessWeigher(base_host.BaseHostWeigher):
27 """Goodness Weigher. Assign weights based on a host's goodness function.
29 Goodness rating is the following:
31 .. code-block:: none
33 0 -- host is a poor choice
34 .
35 .
36 50 -- host is a good choice
37 .
38 .
39 100 -- host is a perfect choice
41 """
43 def _weigh_object(self, host_state, weight_properties):
44 """Determine host's goodness rating based on a goodness_function."""
45 stats = self._generate_stats(host_state, weight_properties)
46 LOG.debug("Checking host '%s'", stats['host_stats']['host'])
47 result = self._check_goodness_function(stats)
48 LOG.debug("Goodness: %s", result)
49 LOG.debug("Done checking host '%s'", stats['host_stats']['host'])
51 return result
53 def _check_goodness_function(self, stats):
54 """Gets a host's goodness rating based on its goodness function."""
56 goodness_rating = 0
58 if stats['goodness_function'] is None:
59 LOG.warning("Goodness function not set :: defaulting to "
60 "minimal goodness rating of 0.")
61 else:
62 try:
63 goodness_result = self._run_evaluator(
64 stats['goodness_function'],
65 stats)
66 except Exception as ex:
67 LOG.warning("Error in goodness_function function "
68 "'%(function)s' : '%(error)s' :: Defaulting "
69 "to a goodness of 0.",
70 {'function': stats['goodness_function'],
71 'error': ex, })
72 return goodness_rating
74 if type(goodness_result) is bool:
75 if goodness_result: 75 ↛ 85line 75 didn't jump to line 85 because the condition on line 75 was always true
76 goodness_rating = 100
77 elif goodness_result < 0 or goodness_result > 100:
78 LOG.warning("Invalid goodness result. Result must be "
79 "between 0 and 100. Result generated: '%s' "
80 ":: Defaulting to a goodness of 0.",
81 goodness_result)
82 else:
83 goodness_rating = goodness_result
85 msg = "Goodness function result for host %(host)s: %(result)s."
86 args = {'host': stats['host_stats']['host'],
87 'result': str(goodness_rating)}
88 LOG.info(msg, args)
90 return goodness_rating
92 def _run_evaluator(self, func, stats):
93 """Evaluates a given function using the provided available stats."""
94 host_stats = stats['host_stats']
95 host_caps = stats['host_caps']
96 extra_specs = stats['extra_specs']
97 share_stats = stats['share_stats']
99 result = evaluator.evaluate(
100 func,
101 extra=extra_specs,
102 stats=host_stats,
103 capabilities=host_caps,
104 share=share_stats)
106 return result
108 def _generate_stats(self, host_state, weight_properties):
109 """Generates statistics from host and share data."""
111 goodness_function = None
113 if ('goodness_function' in host_state.capabilities and
114 host_state.capabilities['goodness_function'] is not None):
115 goodness_function = str(
116 host_state.capabilities['goodness_function'])
118 stats = utils.generate_stats(host_state, weight_properties)
120 stats['goodness_function'] = goodness_function
122 return stats