Coverage for manila/scheduler/weighers/capacity.py: 94%

47 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2026-02-18 22:19 +0000

1# Copyright (c) 2012 OpenStack, LLC. 

2# Copyright (c) 2015 EMC Corporation 

3# 

4# All Rights Reserved. 

5# 

6# Licensed under the Apache License, Version 2.0 (the "License"); you may 

7# not use this file except in compliance with the License. You may obtain 

8# 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, WITHOUT 

14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 

15# License for the specific language governing permissions and limitations 

16# under the License. 

17""" 

18Capacity Weigher. Weigh hosts by their virtual or actual free capacity. 

19 

20For thin provisioning, weigh hosts by their virtual free capacity calculated 

21by the total capacity multiplied by the max over subscription ratio and 

22subtracting the provisioned capacity; Otherwise, weigh hosts by their actual 

23free capacity, taking into account the reserved space. 

24 

25The default is to spread shares across all hosts evenly. If you prefer 

26stacking, you can set the 'capacity_weight_multiplier' option to a negative 

27number and the weighing has the opposite effect of the default. 

28""" 

29 

30import math 

31 

32from oslo_config import cfg 

33 

34from manila.scheduler import utils 

35from manila.scheduler.weighers import base_host 

36 

37capacity_weight_opts = [ 

38 cfg.FloatOpt('capacity_weight_multiplier', 

39 default=1.0, 

40 help='Multiplier used for weighing share capacity. ' 

41 'Negative numbers mean to stack vs spread.'), 

42] 

43 

44CONF = cfg.CONF 

45CONF.register_opts(capacity_weight_opts) 

46 

47 

48class CapacityWeigher(base_host.BaseHostWeigher): 

49 def weight_multiplier(self): 

50 """Override the weight multiplier.""" 

51 return CONF.capacity_weight_multiplier 

52 

53 def _weigh_object(self, host_state, weight_properties): 

54 """Higher weighers win. We want spreading to be the default.""" 

55 if weight_properties.get('snapshot_id'): 55 ↛ 56line 55 didn't jump to line 56 because the condition on line 55 was never true

56 reserved = float(host_state.reserved_snapshot_percentage) / 100 

57 elif weight_properties.get('is_share_extend'): 57 ↛ 58line 57 didn't jump to line 58 because the condition on line 57 was never true

58 reserved = float(host_state.reserved_share_extend_percentage) / 100 

59 else: 

60 reserved = float(host_state.reserved_percentage) / 100 

61 

62 free_space = host_state.free_capacity_gb 

63 total_space = host_state.total_capacity_gb 

64 if 'unknown' in (total_space, free_space): 

65 # NOTE(u_glide): "unknown" capacity always sorts to the bottom 

66 if CONF.capacity_weight_multiplier > 0: 

67 free = float('-inf') 

68 else: 

69 free = float('inf') 

70 else: 

71 total = float(total_space) 

72 

73 share_type = weight_properties.get('share_type', {}) 

74 use_thin_logic = utils.use_thin_logic(share_type) 

75 thin_provisioning = utils.thin_provisioning( 

76 host_state.thin_provisioning) 

77 

78 if use_thin_logic and thin_provisioning: 

79 # NOTE(xyang): Calculate virtual free capacity for thin 

80 # provisioning. 

81 free = math.floor( 

82 total * host_state.max_over_subscription_ratio - 

83 host_state.provisioned_capacity_gb - 

84 total * reserved) 

85 else: 

86 # NOTE(xyang): Calculate how much free space is left after 

87 # taking into account the reserved space. 

88 free = math.floor(free_space - total * reserved) 

89 return free 

90 

91 def weigh_objects(self, weighed_obj_list, weight_properties): 

92 weights = super(CapacityWeigher, self).weigh_objects(weighed_obj_list, 

93 weight_properties) 

94 # NOTE(u_glide): Replace -inf with (minimum - 1) and 

95 # inf with (maximum + 1) to avoid errors in 

96 # manila.scheduler.weighers.base.normalize() method 

97 if self.minval == float('-inf'): 

98 self.minval = self.maxval 

99 for val in weights: 

100 if float('-inf') < val < self.minval: 

101 self.minval = val 

102 self.minval -= 1 

103 return [self.minval if w == float('-inf') else w for w in weights] 

104 elif self.maxval == float('inf'): 

105 self.maxval = self.minval 

106 for val in weights: 

107 if self.maxval < val < float('inf'): 

108 self.maxval = val 

109 self.maxval += 1 

110 return [self.maxval if w == float('inf') else w for w in weights] 

111 else: 

112 return weights