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

102 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-24 22:41 -0600

1"""Index Entity Class""" 

2import typing as t 

3from os import getenv 

4from elasticsearch8 import Elasticsearch 

5from es_wait import Exists 

6from es_testbed.defaults import PAUSE_DEFAULT, PAUSE_ENVVAR, TIMEOUT_DEFAULT, TIMEOUT_ENVVAR 

7from es_testbed.exceptions import NameChanged, ResultNotExpected 

8from es_testbed.helpers import es_api 

9from es_testbed.helpers.utils import getlogger, mounted_name 

10from .entity import Entity 

11from ..ilm import IlmTracker 

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

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

14 

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

16 

17class Index(Entity): 

18 def __init__( 

19 self, 

20 client: Elasticsearch = None, 

21 name: str = None, 

22 autobuild: t.Optional[bool] = True, 

23 snapmgr = None, 

24 policy_name: str = None, 

25 ): 

26 super().__init__(client=client, name=name, autobuild=autobuild) 

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

28 self.policy_name = policy_name 

29 self.ilm_tracker = None 

30 self.snapmgr = snapmgr 

31 self.track_ilm(self.name) 

32 

33 @property 

34 def _get_target(self) -> str: 

35 target = None 

36 phases = self.ilm_tracker.policy_phases 

37 curr = self.ilm_tracker.explain.phase 

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

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

40 target = curr # Keep the same 

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

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

43 target = 'cold' 

44 elif curr == 'cold': 

45 target = 'frozen' 

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

47 target = curr 

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

49 target = 'cold' 

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

51 target = 'frozen' 

52 return target 

53 

54 @property 

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

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

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

58 

59 def _loop_until_target(self): 

60 current, target = self.phase_tuple 

61 while current != target: 

62 self.logger.debug('Attempting to move %s to ILM phase %s', self.name, target) 

63 self.ilm_tracker.advance(phase=target) 

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

65 newidx = mounted_name(self.name, target) 

66 self.logger.debug('Waiting for ILM phase change to complete. New index: %s', newidx) 

67 kwargs = { 

68 'name': newidx, 'kind': 'index', 'pause': PAUSE_VALUE, 'timeout': TIMEOUT_VALUE} 

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

70 test.wait_for_it() 

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

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

73 self.name = newidx 

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

75 current, target = self.phase_tuple 

76 

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

78 """If we are NOT using ILM but have specified searchable snapshots in the plan entities""" 

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

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

81 # Replace self.name with the renamed name 

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

83 

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

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

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

87 if self.am_i_write_idx: 

88 self.logger.info( 

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

90 return 

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

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

93 self.manual_ss(scheme) 

94 return 

95 current = self.ilm_tracker.explain.phase 

96 target = self._get_target 

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

98 self.logger.debug('Attempting to move %s to ILM phase %s', self.name, target) 

99 self.ilm_tracker.advance(phase=target) 

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

101 newidx = mounted_name(self.name, target) 

102 self.logger.debug('Waiting for ILM phase change to complete. New index: %s', newidx) 

103 kwargs = { 

104 'name': newidx, 'kind': 'index', 'pause': PAUSE_VALUE, 'timeout': TIMEOUT_VALUE} 

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

106 test.wait_for_it() 

107 try: 

108 self.ilm_tracker.wait4complete() 

109 except NameChanged: 

110 try: 

111 self.track_ilm(newidx) 

112 self.ilm_tracker.wait4complete() 

113 except NameChanged as err: 

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

115 raise ResultNotExpected from err 

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

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

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

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

120 self.snapmgr.add_existing(snapname) 

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

122 self.name = newidx 

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

124 

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

126 """ 

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

128 Name as an arg makes it configurable 

129 """ 

130 if self.policy_name: 

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

132 self.ilm_tracker.update()