Coverage for curator/actions/index_settings.py: 100%
61 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-20 21:00 -0600
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-20 21:00 -0600
1"""Index settings action class"""
2import logging
3# pylint: disable=import-error
4from curator.exceptions import ActionError, ConfigurationError, MissingArgument
5from curator.helpers.testers import verify_index_list
6from curator.helpers.utils import chunk_index_list, report_failure, show_dry_run, to_csv
8class IndexSettings:
9 """Index Settings Action Class"""
10 def __init__(
11 self, ilo, index_settings=None, ignore_unavailable=False, preserve_existing=False):
12 """
13 :param ilo: An IndexList Object
14 :param index_settings: A settings structure with one or more index settings to change.
15 :param ignore_unavailable: Whether specified concrete indices should be ignored when
16 unavailable (missing or closed)
17 :param preserve_existing: Whether to update existing settings. If set to ``True``, existing
18 settings on an index remain unchanged. The default is ``False``
20 :type ilo: :py:class:`~.curator.indexlist.IndexList`
21 :type index_settings: dict
22 :type ignore_unavailable: bool
23 :type preserve_existing: bool
24 """
25 if index_settings is None:
26 index_settings = {}
27 verify_index_list(ilo)
28 if not index_settings:
29 raise MissingArgument('Missing value for "index_settings"')
30 #: The :py:class:`~.curator.indexlist.IndexList` object passed from param ``ilo``
31 self.index_list = ilo
32 #: The :py:class:`~.elasticsearch.Elasticsearch` client object derived from
33 #: :py:attr:`index_list`
34 self.client = ilo.client
35 #: Object attribute that gets the value of param ``index_settings``.
36 self.body = index_settings
37 #: Object attribute that gets the value of param ``ignore_unavailable``.
38 self.ignore_unavailable = ignore_unavailable
39 #: Object attribute that gets the value of param ``preserve_existing``.
40 self.preserve_existing = preserve_existing
42 self.loggit = logging.getLogger('curator.actions.index_settings')
43 self._body_check()
45 def _body_check(self):
46 # The body only passes the skimpiest of requirements by having 'index'
47 # as the only root-level key, and having a 'dict' as its value
48 if len(self.body) == 1:
49 if 'index' in self.body:
50 if isinstance(self.body['index'], dict):
51 return True
52 raise ConfigurationError(f'Bad value for "index_settings": {self.body}')
54 def _static_settings(self):
55 return [
56 'number_of_shards',
57 'shard',
58 'codec',
59 'routing_partition_size',
60 ]
62 def _dynamic_settings(self):
63 return [
64 'number_of_replicas',
65 'auto_expand_replicas',
66 'refresh_interval',
67 'max_result_window',
68 'max_rescore_window',
69 'blocks',
70 'max_refresh_listeners',
71 'mapping',
72 'merge',
73 'translog',
74 ]
76 def _settings_check(self):
77 # Detect if even one index is open. Save all found to open_index_list.
78 open_index_list = []
79 open_indices = False
80 # This action requires index settings and state to be present
81 # Calling these here should not cause undue problems, even if it's a repeat call
82 self.index_list.get_index_state()
83 self.index_list.get_index_settings()
84 for idx in self.index_list.indices:
85 if self.index_list.index_info[idx]['state'] == 'open':
86 open_index_list.append(idx)
87 open_indices = True
88 for k in self.body['index']:
89 if k in self._static_settings():
90 if not self.ignore_unavailable:
91 if open_indices:
92 msg = (
93 f'Static Setting "{k}" detected with open indices: {open_index_list}. '
94 f'Static settings can only be used with closed indices. Recommend '
95 f'filtering out open indices, or setting ignore_unavailable to True'
96 )
97 raise ActionError(msg)
98 elif k in self._dynamic_settings():
99 # Dynamic settings should be appliable to open or closed indices
100 # Act here if the case is different for some settings.
101 pass
102 else:
103 msg = f'"{k}" is not a setting Curator recognizes and may or may not work.'
104 self.loggit.warning(msg)
106 def do_dry_run(self):
107 """Log what the output would be, but take no action."""
108 show_dry_run(self.index_list, 'indexsettings', **self.body)
110 def do_action(self):
111 """
112 :py:meth:`~.elasticsearch.client.IndicesClient.put_settings` in :py:attr:`body` to indices
113 in :py:attr:`index_list`
114 """
115 self._settings_check()
116 # Ensure that the open indices filter applied in _settings_check()
117 # didn't result in an empty list (or otherwise empty)
118 self.index_list.empty_list_check()
119 msg = (
120 f'Applying index settings to {len(self.index_list.indices)} indices: '
121 f'{self.index_list.indices}'
122 )
123 self.loggit.info(msg)
124 try:
125 index_lists = chunk_index_list(self.index_list.indices)
126 for lst in index_lists:
127 response = self.client.indices.put_settings(
128 index=to_csv(lst), body=self.body,
129 ignore_unavailable=self.ignore_unavailable,
130 preserve_existing=self.preserve_existing
131 )
132 self.loggit.debug('PUT SETTINGS RESPONSE: %s', response)
133 # pylint: disable=broad-except
134 except Exception as err:
135 report_failure(err)