Parse the output of a remote or local command and return its result. Raise exceptions if the command has a non-zero exitcode or its output is not valid JSON or is not in the expected format, usually ``{"local": {"return": value}}`` (+ optional keys in the "local" dict).
(stdout, stderr, retcode, result_only=False)
| 320 | |
| 321 | |
| 322 | def parse_ret(stdout, stderr, retcode, result_only=False): |
| 323 | """ |
| 324 | Parse the output of a remote or local command and return its |
| 325 | result. Raise exceptions if the command has a non-zero exitcode |
| 326 | or its output is not valid JSON or is not in the expected format, |
| 327 | usually ``{"local": {"return": value}}`` (+ optional keys in the "local" dict). |
| 328 | """ |
| 329 | try: |
| 330 | retcode = int(retcode) |
| 331 | except (TypeError, ValueError): |
| 332 | log.warning("Got an invalid retcode for host: '%s'", retcode) |
| 333 | retcode = 1 |
| 334 | |
| 335 | if "Permission denied" in stderr: |
| 336 | # -failed to upload file- is detecting scp errors |
| 337 | # Errors to ignore when Permission denied is in the stderr. For example |
| 338 | # scp can get a permission denied on the target host, but they where |
| 339 | # able to accurate authenticate against the box |
| 340 | ignore_err = ["failed to upload file"] |
| 341 | check_err = [x for x in ignore_err if stderr.count(x)] |
| 342 | if not check_err: |
| 343 | raise SSHPermissionDeniedError( |
| 344 | stdout=stdout, stderr=stderr, retcode=retcode |
| 345 | ) |
| 346 | |
| 347 | result = NOT_SET |
| 348 | error = None |
| 349 | data = None |
| 350 | |
| 351 | try: |
| 352 | data = salt.utils.json.find_json(stdout) |
| 353 | except ValueError: |
| 354 | # No valid JSON output was found |
| 355 | error = SSHReturnDecodeError |
| 356 | else: |
| 357 | if isinstance(data, dict) and len(data) < 2 and "local" in data: |
| 358 | result = data["local"] |
| 359 | try: |
| 360 | remote_retcode = result["retcode"] |
| 361 | except (KeyError, TypeError): |
| 362 | pass |
| 363 | else: |
| 364 | try: |
| 365 | # Ensure a reported local retcode is kept (at least) |
| 366 | retcode = max(retcode, remote_retcode) |
| 367 | except (TypeError, ValueError): |
| 368 | log.warning( |
| 369 | "Host reported an invalid retcode: '%s'", remote_retcode |
| 370 | ) |
| 371 | retcode = max(retcode, 1) |
| 372 | |
| 373 | if not isinstance(result, dict): |
| 374 | # When a command has failed, the return is dumped as-is |
| 375 | # without declaring it as a result, usually a string or list. |
| 376 | error = SSHCommandExecutionError |
| 377 | elif result_only: |
| 378 | try: |
| 379 | result = result["return"] |
no test coverage detected