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
« 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))
15# pylint: disable=missing-docstring,too-many-arguments
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)
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
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
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
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'])
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
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()