Conditions | 9 |
Total Lines | 140 |
Lines | 0 |
Ratio | 0 % |
Changes | 4 | ||
Bugs | 0 | Features | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
1 | # Licensed to the StackStorm, Inc ('StackStorm') under one or more |
||
99 | def run(self, action_parameters): |
||
100 | env_vars = self._env |
||
101 | |||
102 | if not self.entry_point: |
||
103 | script_action = False |
||
104 | command = self.runner_parameters.get(RUNNER_COMMAND, None) |
||
105 | action = ShellCommandAction(name=self.action_name, |
||
106 | action_exec_id=str(self.liveaction_id), |
||
107 | command=command, |
||
108 | user=self._user, |
||
109 | env_vars=env_vars, |
||
110 | sudo=self._sudo, |
||
111 | timeout=self._timeout, |
||
112 | sudo_password=self._sudo_password) |
||
113 | else: |
||
114 | script_action = True |
||
115 | script_local_path_abs = self.entry_point |
||
116 | positional_args, named_args = self._get_script_args(action_parameters) |
||
117 | named_args = self._transform_named_args(named_args) |
||
118 | |||
119 | action = ShellScriptAction(name=self.action_name, |
||
120 | action_exec_id=str(self.liveaction_id), |
||
121 | script_local_path_abs=script_local_path_abs, |
||
122 | named_args=named_args, |
||
123 | positional_args=positional_args, |
||
124 | user=self._user, |
||
125 | env_vars=env_vars, |
||
126 | sudo=self._sudo, |
||
127 | timeout=self._timeout, |
||
128 | cwd=self._cwd, |
||
129 | sudo_password=self._sudo_password) |
||
130 | |||
131 | args = action.get_full_command_string() |
||
132 | sanitized_args = action.get_sanitized_full_command_string() |
||
133 | |||
134 | # For consistency with the old Fabric based runner, make sure the file is executable |
||
135 | if script_action: |
||
136 | args = 'chmod +x %s ; %s' % (script_local_path_abs, args) |
||
137 | sanitized_args = 'chmod +x %s ; %s' % (script_local_path_abs, sanitized_args) |
||
138 | |||
139 | env = os.environ.copy() |
||
140 | |||
141 | # Include user provided env vars (if any) |
||
142 | env.update(env_vars) |
||
143 | |||
144 | # Include common st2 env vars |
||
145 | st2_env_vars = self._get_common_action_env_variables() |
||
146 | env.update(st2_env_vars) |
||
147 | |||
148 | LOG.info('Executing action via LocalRunner: %s', self.runner_id) |
||
149 | LOG.info('[Action info] name: %s, Id: %s, command: %s, user: %s, sudo: %s' % |
||
150 | (action.name, action.action_exec_id, sanitized_args, action.user, action.sudo)) |
||
151 | |||
152 | stdout = StringIO() |
||
153 | stderr = StringIO() |
||
154 | |||
155 | store_execution_stdout_line = functools.partial(store_execution_output_data, |
||
156 | output_type='stdout') |
||
157 | store_execution_stderr_line = functools.partial(store_execution_output_data, |
||
158 | output_type='stderr') |
||
159 | |||
160 | read_and_store_stdout = make_read_and_store_stream_func(execution_db=self.execution, |
||
161 | action_db=self.action, store_data_func=store_execution_stdout_line) |
||
162 | read_and_store_stderr = make_read_and_store_stream_func(execution_db=self.execution, |
||
163 | action_db=self.action, store_data_func=store_execution_stderr_line) |
||
164 | |||
165 | # If sudo password is provided, pass it to the subprocess via stdin> |
||
166 | # Note: We don't need to explicitly escape the argument because we pass command as a list |
||
167 | # to subprocess.Popen and all the arguments are escaped by the function. |
||
168 | if self._sudo_password: |
||
169 | LOG.debug('Supplying sudo password via stdin') |
||
170 | echo_process = subprocess.Popen(['echo', self._sudo_password + '\n'], |
||
171 | stdout=subprocess.PIPE) |
||
172 | stdin = echo_process.stdout |
||
173 | else: |
||
174 | stdin = None |
||
175 | |||
176 | # Make sure os.setsid is called on each spawned process so that all processes |
||
177 | # are in the same group. |
||
178 | |||
179 | # Process is started as sudo -u {{system_user}} -- bash -c {{command}}. Introduction of the |
||
180 | # bash means that multiple independent processes are spawned without them being |
||
181 | # children of the process we have access to and this requires use of pkill. |
||
182 | # Ideally os.killpg should have done the trick but for some reason that failed. |
||
183 | # Note: pkill will set the returncode to 143 so we don't need to explicitly set |
||
184 | # it to some non-zero value. |
||
185 | exit_code, stdout, stderr, timed_out = shell.run_command(cmd=args, |
||
186 | stdin=stdin, |
||
187 | stdout=subprocess.PIPE, |
||
188 | stderr=subprocess.PIPE, |
||
189 | shell=True, |
||
190 | cwd=self._cwd, |
||
191 | env=env, |
||
192 | timeout=self._timeout, |
||
193 | preexec_func=os.setsid, |
||
194 | kill_func=kill_process, |
||
195 | read_stdout_func=read_and_store_stdout, |
||
196 | read_stderr_func=read_and_store_stderr, |
||
197 | read_stdout_buffer=stdout, |
||
198 | read_stderr_buffer=stderr) |
||
199 | |||
200 | error = None |
||
201 | |||
202 | if timed_out: |
||
203 | error = 'Action failed to complete in %s seconds' % (self._timeout) |
||
204 | exit_code = -1 * exit_code_constants.SIGKILL_EXIT_CODE |
||
205 | |||
206 | # Detect if user provided an invalid sudo password or sudo is not configured for that user |
||
207 | if self._sudo_password: |
||
208 | if re.search('sudo: \d+ incorrect password attempts', stderr): |
||
|
|||
209 | match = re.search('\[sudo\] password for (.+?)\:', stderr) |
||
210 | |||
211 | if match: |
||
212 | username = match.groups()[0] |
||
213 | else: |
||
214 | username = 'unknown' |
||
215 | |||
216 | error = ('Invalid sudo password provided or sudo is not configured for this user ' |
||
217 | '(%s)' % (username)) |
||
218 | exit_code = -1 |
||
219 | |||
220 | succeeded = (exit_code == exit_code_constants.SUCCESS_EXIT_CODE) |
||
221 | |||
222 | result = { |
||
223 | 'failed': not succeeded, |
||
224 | 'succeeded': succeeded, |
||
225 | 'return_code': exit_code, |
||
226 | 'stdout': strip_shell_chars(stdout), |
||
227 | 'stderr': strip_shell_chars(stderr) |
||
228 | } |
||
229 | |||
230 | if error: |
||
231 | result['error'] = error |
||
232 | |||
233 | status = PROC_EXIT_CODE_TO_LIVEACTION_STATUS_MAP.get( |
||
234 | str(exit_code), |
||
235 | action_constants.LIVEACTION_STATUS_FAILED |
||
236 | ) |
||
237 | |||
238 | return (status, jsonify.json_loads(result, LocalShellRunner.KEYS_TO_TRANSFORM), None) |
||
239 | |||
247 |
Escape sequences in Python are generally interpreted according to rules similar to standard C. Only if strings are prefixed with
r
orR
are they interpreted as regular expressions.The escape sequence that was used indicates that you might have intended to write a regular expression.
Learn more about the available escape sequences. in the Python documentation.