Coverage for /Users/buh/.pyenv/versions/3.12.2/envs/es-testbed/lib/python3.12/site-packages/es_testbed/classes/entities/index.py: 80%

88 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-27 20:59 -0600

1"""Index Entity Class""" 

2 

3import typing as t 

4from os import getenv 

5from es_wait import Exists 

6from es_testbed.defaults import ( 

7 PAUSE_DEFAULT, 

8 PAUSE_ENVVAR, 

9 TIMEOUT_DEFAULT, 

10 TIMEOUT_ENVVAR, 

11) 

12from es_testbed.exceptions import NameChanged, ResultNotExpected 

13from es_testbed.helpers import es_api 

14from es_testbed.helpers.utils import getlogger, mounted_name 

15from .entity import Entity 

16from ..ilm import IlmTracker 

17 

18if t.TYPE_CHECKING: 18 ↛ 19line 18 didn't jump to line 19, because the condition on line 18 was never true

19 from elasticsearch8 import Elasticsearch 

20 

21PAUSE_VALUE = float(getenv(PAUSE_ENVVAR, default=PAUSE_DEFAULT)) 

22TIMEOUT_VALUE = float(getenv(TIMEOUT_ENVVAR, default=TIMEOUT_DEFAULT)) 

23 

24# pylint: disable=missing-docstring,too-many-arguments 

25 

26 

27class Index(Entity): 

28 

29 def __init__( 

30 self, 

31 client: 'Elasticsearch', 

32 name: t.Union[str, None] = None, 

33 snapmgr=None, 

34 policy_name: str = None, 

35 ): 

36 super().__init__(client=client, name=name) 

37 self.logger = getlogger('es_testbed.Index') 

38 self.policy_name = policy_name 

39 self.ilm_tracker = None 

40 self.snapmgr = snapmgr 

41 self.track_ilm(self.name) 

42 

43 @property 

44 def _get_target(self) -> str: 

45 target = None 

46 phases = self.ilm_tracker.policy_phases 

47 curr = self.ilm_tracker.explain.phase 

48 if not bool(('cold' in phases) or ('frozen' in phases)): 48 ↛ 49line 48 didn't jump to line 49, because the condition on line 48 was never true

49 self.logger.info('ILM Policy for "%s" has no cold/frozen phases', self.name) 

50 target = curr # Keep the same 

51 if bool(('cold' in phases) and ('frozen' in phases)): 51 ↛ 52line 51 didn't jump to line 52, because the condition on line 51 was never true

52 if self.ilm_tracker.pname(curr) < self.ilm_tracker.pname('cold'): 

53 target = 'cold' 

54 elif curr == 'cold': 

55 target = 'frozen' 

56 elif self.ilm_tracker.pname(curr) >= self.ilm_tracker.pname('frozen'): 

57 target = curr 

58 elif bool(('cold' in phases) and ('frozen' not in phases)): 

59 target = 'cold' 

60 elif bool(('cold' not in phases) and ('frozen' in phases)): 60 ↛ 62line 60 didn't jump to line 62, because the condition on line 60 was never false

61 target = 'frozen' 

62 return target 

63 

64 @property 

65 def phase_tuple(self) -> t.Tuple[str, str]: 

66 """Return the current phase and the target phase as a Tuple""" 

67 return self.ilm_tracker.explain.phase, self._get_target 

68 

69 # This is maybe unnecessary. This is for progressing ILM, e.g. from 

70 # hot -> warm -> cold -> frozen (and even through delete). 

71 # 

72 # def _loop_until_target(self) -> None: 

73 # current, target = self.phase_tuple 

74 # while current != target: 

75 # self.logger.debug( 

76 # 'Attempting to move %s to ILM phase %s', self.name, target 

77 # ) 

78 # self.ilm_tracker.advance(phase=target) 

79 # # At this point, it's "in" a searchable tier, but the index name hasn't 

80 # # changed yet 

81 # newidx = mounted_name(self.name, target) 

82 # self.logger.debug( 

83 # 'Waiting for ILM phase change to complete. New index: %s', newidx 

84 # ) 

85 # kwargs = { 

86 # 'name': newidx, 

87 # 'kind': 'index', 

88 # 'pause': PAUSE_VALUE, 

89 # 'timeout': TIMEOUT_VALUE, 

90 # } 

91 # test = Exists(self.client, **kwargs) 

92 # test.wait_for_it() 

93 # self.logger.info('ILM advance to phase %s completed', target) 

94 # self.aka.append(self.name) # Append the old name to the AKA list 

95 # self.name = newidx 

96 # self.track_ilm(self.name) # Refresh the ilm_tracker with the new name 

97 # current, target = self.phase_tuple 

98 

99 def manual_ss(self, scheme) -> None: 

100 """ 

101 If we are NOT using ILM but have specified searchable snapshots in the plan 

102 entities 

103 """ 

104 if 'searchable' in scheme and scheme['searchable'] is not None: 

105 self.snapmgr.add(self.name, scheme['searchable']) 

106 # Replace self.name with the renamed name 

107 self.name = mounted_name(self.name, scheme['searchable']) 

108 

109 def mount_ss(self, scheme: dict) -> None: 

110 """If the index is planned to become a searchable snapshot, we do that now""" 

111 self.logger.debug('Checking if %s should be a searchable snapshot', self.name) 

112 if self.am_i_write_idx: 

113 self.logger.info( 

114 '%s is the write_index. Cannot mount as searchable snapshot', self.name 

115 ) 

116 return 

117 if not self.policy_name: # If we have this, chances are we have a policy 

118 self.logger.debug('No ILM policy found. Switching to manual mode') 

119 self.manual_ss(scheme) 

120 return 

121 current = self.ilm_tracker.explain.phase 

122 target = self._get_target 

123 if current != target: 123 ↛ exitline 123 didn't return from function 'mount_ss', because the condition on line 123 was never false

124 self.logger.debug( 

125 'Attempting to move %s to ILM phase %s', self.name, target 

126 ) 

127 self.ilm_tracker.advance(phase=target) 

128 # At this point, it's "in" a searchable tier, but the index name hasn't 

129 # changed yet 

130 newidx = mounted_name(self.name, target) 

131 self.logger.debug( 

132 'Waiting for ILM phase change to complete. New index: %s', newidx 

133 ) 

134 kwargs = { 

135 'name': newidx, 

136 'kind': 'index', 

137 'pause': PAUSE_VALUE, 

138 'timeout': TIMEOUT_VALUE, 

139 } 

140 test = Exists(self.client, **kwargs) 

141 test.wait_for_it() 

142 try: 

143 self.ilm_tracker.wait4complete() 

144 except NameChanged: 

145 try: 

146 self.track_ilm(newidx) 

147 self.ilm_tracker.wait4complete() 

148 except NameChanged as err: 

149 self.logger.critical('Index name mismatch. Cannot continue') 

150 raise ResultNotExpected from err 

151 self.logger.info('ILM advance to phase %s completed', target) 

152 self.logger.debug('Getting snapshot name for tracking...') 

153 snapname = es_api.snapshot_name(self.client, newidx) 

154 self.logger.debug('Snapshot %s backs %s', snapname, newidx) 

155 self.snapmgr.add_existing(snapname) 

156 self.aka.append(self.name) # Append the old name to the AKA list 

157 self.name = newidx 

158 self.track_ilm(self.name) # Refresh the ilm_tracker with the new index name 

159 

160 def track_ilm(self, name: str) -> None: 

161 """ 

162 Get ILM phase information and put it in self.ilm_tracker 

163 Name as an arg makes it configurable 

164 """ 

165 if self.policy_name: 

166 self.ilm_tracker = IlmTracker(self.client, name) 

167 self.ilm_tracker.update()