Coverage for manila/scheduler/filters/affinity.py: 90%

60 statements  

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

1# Copyright (c) 2021 SAP. 

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. 

15 

16from oslo_log import log 

17 

18from manila import exception 

19from manila.scheduler.filters import base_host 

20from manila.share import api 

21 

22LOG = log.getLogger(__name__) 

23 

24AFFINITY_FILTER = 'same_host' 

25ANTI_AFFINITY_FILTER = 'different_host' 

26 

27 

28class AffinityBaseFilter(base_host.BaseHostFilter): 

29 """Base class of affinity filters""" 

30 _filter_type = None 

31 

32 def __init__(self): 

33 self.share_api = api.API() 

34 

35 def filter_all(self, filter_obj_list, filter_properties): 

36 # _filter_type should be defined in subclass 

37 if self._filter_type is None: 37 ↛ 38line 37 didn't jump to line 38 because the condition on line 37 was never true

38 raise AffinityFilterTypeNotSetError 

39 

40 try: 

41 filter_properties = self._validate(filter_properties) 

42 except SchedulerHintsNotSet: 

43 # AffinityFilter/AntiAffinityFilter is skipped if corresponding 

44 # hint is not set. If the "scheduler_hints" is not set, both 

45 # filters are skipped. 

46 return filter_obj_list 

47 except (exception.InvalidUUID, 

48 exception.ShareNotFound, 

49 exception.ShareInstanceNotFound) as e: 

50 # Stop scheduling share when above errors are caught 

51 LOG.error('%(filter_name)s: %(error)s', { 

52 'filter_name': self.__class__.__name__, 

53 'error': e}) 

54 return None 

55 else: 

56 # Return list of hosts which pass the function host_passes() 

57 # overriden in AffinityFilter and AntiAffinityFilter. 

58 return [obj for obj in filter_obj_list 

59 if self._filter_one(obj, filter_properties)] 

60 

61 def _validate(self, filter_properties): 

62 context = filter_properties['context'] 

63 hints = filter_properties.get('scheduler_hints') 

64 

65 if hints is None: 

66 raise SchedulerHintsNotSet 

67 else: 

68 share_uuids = hints.get(self._filter_type) 

69 if share_uuids is None: 

70 raise SchedulerHintsNotSet 

71 

72 share_uuids = share_uuids.split(",") 

73 

74 filter_properties['scheduler_hints'][self._filter_type] = [] 

75 

76 filtered_hosts = [] 

77 for uuid in share_uuids: 

78 try: 

79 share = self.share_api.get(context, uuid) 

80 except exception.NotFound: 

81 raise exception.ShareNotFound(uuid) 

82 instances = share.get('instances') 

83 if len(instances) == 0: 83 ↛ 84line 83 didn't jump to line 84 because the condition on line 83 was never true

84 raise exception.ShareInstanceNotFound(share_instance_id=uuid) 

85 filtered_hosts.append( 

86 [instance.get('host') for instance in instances]) 

87 

88 if self._filter_type == AFFINITY_FILTER: 

89 filter_properties['scheduler_hints'][self._filter_type] = list( 

90 set.intersection(*map(set, filtered_hosts))) 

91 else: 

92 filter_properties['scheduler_hints'][self._filter_type] = list( 

93 set.union(*map(set, filtered_hosts))) 

94 

95 return filter_properties 

96 

97 

98class AffinityFilter(AffinityBaseFilter): 

99 _filter_type = AFFINITY_FILTER 

100 

101 def host_passes(self, host_state, filter_properties): 

102 allowed_hosts = \ 

103 filter_properties['scheduler_hints'][self._filter_type] 

104 return host_state.host in allowed_hosts 

105 

106 

107class AntiAffinityFilter(AffinityBaseFilter): 

108 _filter_type = ANTI_AFFINITY_FILTER 

109 

110 def host_passes(self, host_state, filter_properties): 

111 forbidden_hosts = \ 

112 filter_properties['scheduler_hints'][self._filter_type] 

113 return host_state.host not in forbidden_hosts 

114 

115 

116class SchedulerHintsNotSet(Exception): 

117 pass 

118 

119 

120class AffinityFilterTypeNotSetError(Exception): 

121 pass