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
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-27 20:59 -0600
1"""Index Entity Class"""
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
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
21PAUSE_VALUE = float(getenv(PAUSE_ENVVAR, default=PAUSE_DEFAULT))
22TIMEOUT_VALUE = float(getenv(TIMEOUT_ENVVAR, default=TIMEOUT_DEFAULT))
24# pylint: disable=missing-docstring,too-many-arguments
27class Index(Entity):
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)
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
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
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
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'])
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
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()