Coverage for watcher/applier/actions/base.py: 95%

37 statements  

« prev     ^ index     » next       coverage.py v7.8.2, created at 2025-06-17 12:22 +0000

1# -*- encoding: utf-8 -*- 

2# Copyright (c) 2015 b<>com 

3# 

4# Authors: Jean-Emile DARTOIS <jean-emile.dartois@b-com.com> 

5# 

6# Licensed under the Apache License, Version 2.0 (the "License"); 

7# you may not use this file except in compliance with the License. 

8# You may obtain a copy of the License at 

9# 

10# http://www.apache.org/licenses/LICENSE-2.0 

11# 

12# Unless required by applicable law or agreed to in writing, software 

13# distributed under the License is distributed on an "AS IS" BASIS, 

14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 

15# implied. 

16# See the License for the specific language governing permissions and 

17# limitations under the License. 

18 

19import abc 

20 

21import jsonschema 

22 

23from watcher.common import clients 

24from watcher.common.loader import loadable 

25 

26 

27class BaseAction(loadable.Loadable, metaclass=abc.ABCMeta): 

28 # NOTE(jed): by convention we decided 

29 # that the attribute "resource_id" is the unique id of 

30 # the resource to which the Action applies to allow us to use it in the 

31 # watcher dashboard and will be nested in input_parameters 

32 RESOURCE_ID = 'resource_id' 

33 

34 # Add action class name to the list, if implementing abort. 

35 ABORT_TRUE = ['Sleep', 'Nop'] 

36 

37 def __init__(self, config, osc=None): 

38 """Constructor 

39 

40 :param config: A mapping containing the configuration of this action 

41 :type config: dict 

42 :param osc: an OpenStackClients instance, defaults to None 

43 :type osc: :py:class:`~.OpenStackClients` instance, optional 

44 """ 

45 super(BaseAction, self).__init__(config) 

46 self._input_parameters = {} 

47 self._osc = osc 

48 

49 @property 

50 def osc(self): 

51 if not self._osc: 

52 self._osc = clients.OpenStackClients() 

53 return self._osc 

54 

55 @property 

56 def input_parameters(self): 

57 return self._input_parameters 

58 

59 @input_parameters.setter 

60 def input_parameters(self, p): 

61 self._input_parameters = p 

62 

63 @property 

64 def resource_id(self): 

65 return self.input_parameters[self.RESOURCE_ID] 

66 

67 @classmethod 

68 def get_config_opts(cls): 

69 """Defines the configuration options to be associated to this loadable 

70 

71 :return: A list of configuration options relative to this Loadable 

72 :rtype: list of :class:`oslo_config.cfg.Opt` instances 

73 """ 

74 return [] 

75 

76 @abc.abstractmethod 

77 def execute(self): 

78 """Executes the main logic of the action 

79 

80 This method can be used to perform an action on a given set of input 

81 parameters to accomplish some type of operation. This operation may 

82 return a boolean value as a result of its execution. If False, this 

83 will be considered as an error and will then trigger the reverting of 

84 the actions. 

85 

86 :returns: A flag indicating whether or not the action succeeded 

87 :rtype: bool 

88 """ 

89 raise NotImplementedError() 

90 

91 @abc.abstractmethod 

92 def revert(self): 

93 """Revert this action 

94 

95 This method should rollback the resource to its initial state in the 

96 event of a faulty execution. This happens when the action raised an 

97 exception during its :py:meth:`~.BaseAction.execute`. 

98 """ 

99 raise NotImplementedError() 

100 

101 @abc.abstractmethod 

102 def pre_condition(self): 

103 """Hook: called before the execution of an action 

104 

105 This method can be used to perform some initializations or to make 

106 some more advanced validation on its input parameters. So if you wish 

107 to block its execution based on this factor, `raise` the related 

108 exception. 

109 """ 

110 raise NotImplementedError() 

111 

112 @abc.abstractmethod 

113 def post_condition(self): 

114 """Hook: called after the execution of an action 

115 

116 This function is called regardless of whether an action succeeded or 

117 not. So you can use it to perform cleanup operations. 

118 """ 

119 raise NotImplementedError() 

120 

121 @property 

122 @abc.abstractmethod 

123 def schema(self): 

124 """Defines a Schema that the input parameters shall comply to 

125 

126 :returns: A schema declaring the input parameters this action should be 

127 provided along with their respective constraints 

128 :rtype: :py:class:`jsonschema.Schema` instance 

129 """ 

130 raise NotImplementedError() 

131 

132 def validate_parameters(self): 

133 jsonschema.validate(self.input_parameters, self.schema) 

134 return True 

135 

136 @abc.abstractmethod 

137 def get_description(self): 

138 """Description of the action""" 

139 raise NotImplementedError() 

140 

141 def check_abort(self): 

142 if self.__class__.__name__ == 'Migrate': 

143 if self.migration_type == self.LIVE_MIGRATION: 143 ↛ 146line 143 didn't jump to line 146 because the condition on line 143 was always true

144 return True 

145 else: 

146 return False 

147 else: 

148 return bool(self.__class__.__name__ in self.ABORT_TRUE)