Coverage for /Users/buh/.pyenv/versions/3.12.2/envs/es-testbed/lib/python3.12/site-packages/es_testbed/classes/base.py: 84%
94 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"""Base TestBed Class"""
3import typing as t
4from datetime import datetime, timezone
5from dotmap import DotMap
6from es_testbed.exceptions import ResultNotExpected
7from es_testbed.defaults import NAMEMAPPER
8from es_testbed.helpers.es_api import delete, get
9from es_testbed.helpers.utils import getlogger
10from .plan import PlanBuilder
11from .entitymgrs import (
12 ComponentMgr,
13 DataStreamMgr,
14 IlmMgr,
15 IndexMgr,
16 SnapshotMgr,
17 TemplateMgr,
18)
20if t.TYPE_CHECKING: 20 ↛ 21line 20 didn't jump to line 21, because the condition on line 20 was never true
21 from elasticsearch8 import Elasticsearch
23# pylint: disable=broad-exception-caught,R0902
26class TestBed:
27 """TestBed Class"""
29 __test__ = False
31 def __init__(
32 self,
33 client: 'Elasticsearch' = None,
34 plan: DotMap = None,
35 autobuild: t.Optional[bool] = False,
36 ):
37 self.logger = getlogger('es_testbed.TestBed')
38 self.client = client
39 if plan is None: 39 ↛ 40line 39 didn't jump to line 40, because the condition on line 39 was never true
40 plan = PlanBuilder().plan # Use defaults
41 self.plan = plan
43 # Set up for tracking
44 self.ilmmgr = None
45 self.componentmgr = None
46 self.templatemgr = None
47 self.snapshotmgr = None
48 self.indexmgr = None
49 self.data_streammgr = None
51 if autobuild: 51 ↛ 52line 51 didn't jump to line 52, because the condition on line 51 was never true
52 self.setup()
54 def _fodder_generator(self):
55 """Method to delete everything matching our pattern(s)"""
56 items = ['index', 'data_stream', 'snapshot', 'template', 'component', 'ilm']
57 for i in items:
58 if i == 'snapshot' and self.plan.repository is None: 58 ↛ 59line 58 didn't jump to line 59, because the condition on line 58 was never true
59 self.logger.debug('No repository, no snapshots.')
60 continue
61 # self.logger.debug('Generating a list of type "%s"', i)
62 pattern = f'*{self.plan.prefix}-{NAMEMAPPER[i]}-{self.plan.uniq}*'
63 entities = get(self.client, i, pattern, repository=self.plan.repository)
64 yield (i, entities)
66 def ilm_polling(self, interval: t.Union[str, None] = None):
67 """Return persistent cluster settings to speed up ILM polling during testing"""
68 return {'indices.lifecycle.poll_interval': interval}
70 def _while(self, kind: str, item: str) -> bool:
71 count = 1
72 success = False
73 exc = None
74 while count < 4 and not success: 74 ↛ 84line 74 didn't jump to line 84, because the condition on line 74 was never false
75 try:
76 success = delete(
77 self.client, kind, item, repository=self.plan.repository
78 )
79 break
80 except ResultNotExpected as err:
81 self.logger.debug('Tried deleting "%s" %s time(s)', item, count)
82 exc = err
83 count += 1
84 if not success: 84 ↛ 85line 84 didn't jump to line 85, because the condition on line 84 was never true
85 self.logger.warning(
86 'Failed to delete "%s" after %s tries. Final error: %s',
87 item,
88 count - 1,
89 exc,
90 )
91 return success
93 def _erase(self, kind: str, lst: t.Sequence[str]) -> None:
94 overall_success = True
95 if not lst:
96 self.logger.debug('%s: nothing to delete.', kind)
97 return True
98 if kind == 'ilm': # ILM policies can't be batch deleted
99 ilm = [self._while(kind, x) for x in lst]
100 overall_success = False not in ilm # No False values == True
101 else:
102 overall_success = self._while(kind, ','.join(lst))
103 return overall_success
105 def setup(self):
106 """Setup the instance"""
107 start = datetime.now(timezone.utc)
108 self.logger.info('Setting: %s', self.ilm_polling(interval='1s'))
109 self.client.cluster.put_settings(persistent=self.ilm_polling(interval='1s'))
110 self.setup_entitymgrs()
111 end = datetime.now(timezone.utc)
112 self.logger.info(
113 'Testbed setup elapsed time: %s', (end - start).total_seconds()
114 )
116 def teardown(self):
117 """Tear down anything we created"""
118 start = datetime.now(timezone.utc)
119 successful = True
120 for kind, list_of_kind in self._fodder_generator():
121 if not self._erase(kind, list_of_kind): 121 ↛ 122line 121 didn't jump to line 122, because the condition on line 121 was never true
122 successful = False
123 self.logger.info(
124 'Restoring ILM polling to default: %s', self.ilm_polling(interval=None)
125 )
126 self.client.cluster.put_settings(persistent=self.ilm_polling(interval=None))
127 end = datetime.now(timezone.utc)
128 self.logger.info(
129 'Testbed teardown elapsed time: %s', (end - start).total_seconds()
130 )
131 if successful: 131 ↛ 134line 131 didn't jump to line 134, because the condition on line 131 was never false
132 self.logger.info('Cleanup successful')
133 else:
134 self.logger.error('Cleanup was unsuccessful/incomplete')
135 self.plan.cleanup = successful
137 def setup_entitymgrs(self):
138 """
139 Setup each EntityMgr child class
140 """
141 kw = {'client': self.client, 'plan': self.plan}
142 self.ilmmgr = IlmMgr(**kw)
143 self.componentmgr = ComponentMgr(**kw)
144 self.templatemgr = TemplateMgr(**kw)
145 self.snapshotmgr = SnapshotMgr(**kw)
146 if self.plan.type == 'indices':
147 self.indexmgr = IndexMgr(**kw, snapmgr=self.snapshotmgr)
148 if self.plan.type == 'data_stream':
149 self.data_streammgr = DataStreamMgr(**kw, snapmgr=self.snapshotmgr)