Coverage for curator/actions/alias.py: 100%

80 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-07-20 21:00 -0600

1"""Alias action""" 

2import logging 

3# pylint: disable=import-error 

4from curator.exceptions import ActionError, MissingArgument, NoIndices 

5from curator.helpers.date_ops import parse_date_pattern, parse_datemath 

6from curator.helpers.testers import verify_index_list 

7from curator.helpers.utils import report_failure 

8 

9class Alias: 

10 """Alias Action Class""" 

11 # pylint: disable=unused-argument 

12 def __init__(self, name=None, extra_settings=None, **kwargs): 

13 """ 

14 :param name: The alias name 

15 :param extra_settings: Extra settings, including filters and routing. For more information 

16 see `here </https://www.elastic.co/guide/en/elasticsearch/reference/8.6/indices-aliases.html>`_. 

17 

18 :type name: str 

19 :type extra_settings: dict 

20 """ 

21 if extra_settings is None: 

22 extra_settings = {} 

23 if not name: 

24 raise MissingArgument('No value for "name" provided.') 

25 #: The :py:func:`~.curator.helpers.date_ops.parse_date_pattern` rendered 

26 #: version of what was passed by param ``name``. 

27 self.name = parse_date_pattern(name) 

28 #: The list of actions to perform. Populated by :py:meth:`~.curator.actions.Alias.add` and 

29 #: :py:meth:`~.curator.actions.Alias.remove` 

30 self.actions = [] 

31 #: The :py:class:`~.elasticsearch.Elasticsearch` client object which will later be set by 

32 #: :py:meth:`~.curator.actions.Alias.add` or :py:meth:`~.curator.actions.Alias.remove` 

33 self.client = None 

34 #: Any extra things to add to the alias, like filters, or routing. Gets the value from 

35 #: param ``extra_settings``. 

36 self.extra_settings = extra_settings 

37 self.loggit = logging.getLogger('curator.actions.alias') 

38 #: Preset default value to ``False``. 

39 self.warn_if_no_indices = False 

40 

41 def add(self, ilo, warn_if_no_indices=False): 

42 """ 

43 Create ``add`` statements for each index in ``ilo`` for :py:attr:`name`, then 

44 append them to :py:attr:`actions`. Add any :py:attr:`extra_settings` that may be there. 

45 

46 :param ilo: An IndexList Object 

47 :type ilo: :py:class:`~.curator.indexlist.IndexList` 

48 """ 

49 verify_index_list(ilo) 

50 self.loggit.debug('ADD -> ILO = %s', ilo) 

51 if not self.client: 

52 self.client = ilo.client 

53 self.name = parse_datemath(self.client, self.name) 

54 try: 

55 ilo.empty_list_check() 

56 except NoIndices as exc: 

57 # Add a warning if there are no indices to add, if so set in options 

58 if warn_if_no_indices: 

59 self.warn_if_no_indices = True 

60 self.loggit.warning( 

61 'No indices found after processing filters. Nothing to add to %s', self.name) 

62 return 

63 # Re-raise the exceptions.NoIndices so it will behave as before 

64 raise NoIndices('No indices to add to alias') from exc 

65 for index in ilo.working_list(): 

66 self.loggit.debug( 

67 'Adding index %s to alias %s with extra settings ' 

68 '%s', index, self.name, self.extra_settings 

69 ) 

70 add_dict = {'add' : {'index' : index, 'alias': self.name}} 

71 add_dict['add'].update(self.extra_settings) 

72 self.actions.append(add_dict) 

73 

74 def remove(self, ilo, warn_if_no_indices=False): 

75 """ 

76 Create ``remove`` statements for each index in ``ilo`` for :py:attr:`name`, 

77 then append them to :py:attr:`actions`. 

78 

79 :param ilo: An IndexList Object 

80 :type ilo: :py:class:`~.curator.indexlist.IndexList` 

81 """ 

82 verify_index_list(ilo) 

83 self.loggit.debug('REMOVE -> ILO = %s', ilo) 

84 if not self.client: 

85 self.client = ilo.client 

86 self.name = parse_datemath(self.client, self.name) 

87 try: 

88 ilo.empty_list_check() 

89 except NoIndices as exc: 

90 # Add a warning if there are no indices to add, if so set in options 

91 if warn_if_no_indices: 

92 self.warn_if_no_indices = True 

93 self.loggit.warning( 

94 'No indices found after processing filters. ' 

95 'Nothing to remove from %s', self.name 

96 ) 

97 return 

98 

99 # Re-raise the exceptions.NoIndices so it will behave as before 

100 raise NoIndices('No indices to remove from alias') from exc 

101 aliases = self.client.indices.get_alias() 

102 for index in ilo.working_list(): 

103 if index in aliases: 

104 self.loggit.debug('Index %s in get_aliases output', index) 

105 # Only remove if the index is associated with the alias 

106 if self.name in aliases[index]['aliases']: 

107 self.loggit.debug('Removing index %s from alias %s', index, self.name) 

108 self.actions.append( 

109 {'remove' : {'index' : index, 'alias': self.name}}) 

110 else: 

111 self.loggit.debug( 

112 'Can not remove: Index %s is not associated with alias %s', index, self.name 

113 ) 

114 

115 def check_actions(self): 

116 """ 

117 :returns: :py:attr:`actions` for use with the 

118 :py:meth:`~.elasticsearch.client.IndicesClient.update_aliases` API call if actions 

119 exist, otherwise an exception is raised. 

120 """ 

121 if not self.actions: 

122 if not self.warn_if_no_indices: 

123 raise ActionError('No "add" or "remove" operations') 

124 raise NoIndices('No "adds" or "removes" found. Taking no action') 

125 self.loggit.debug('Alias actions: %s', self.actions) 

126 

127 return self.actions 

128 

129 def do_dry_run(self): 

130 """Log what the output would be, but take no action.""" 

131 self.loggit.info('DRY-RUN MODE. No changes will be made.') 

132 for item in self.check_actions(): 

133 job = list(item.keys())[0] 

134 index = item[job]['index'] 

135 alias = item[job]['alias'] 

136 # We want our log to look clever, so if job is "remove", strip the 

137 # 'e' so "remove" can become "removing". "adding" works already. 

138 msg = ( 

139 f"DRY-RUN: alias: {job.rstrip('e')}ing index \"{index}\" " 

140 f"{'to' if job == 'add' else 'from'} alias \"{alias}\"" 

141 ) 

142 self.loggit.info(msg) 

143 

144 def do_action(self): 

145 """ 

146 :py:meth:`~.elasticsearch.client.IndicesClient.update_aliases` for :py:attr:`name` with 

147 :py:attr:`actions` 

148 """ 

149 self.loggit.info('Updating aliases...') 

150 self.loggit.info('Alias actions: %s', self.actions) 

151 try: 

152 self.client.indices.update_aliases(actions=self.actions) 

153 # pylint: disable=broad-except 

154 except Exception as err: 

155 report_failure(err)