Skip to content

Commit

Permalink
[PLAT-16198] Ansible error parsing in shell process handler does not …
Browse files Browse the repository at this point in the history
…work

Summary: It was parsing the wrong input to find the ansible task error. Ansible task errors are in stderr. Python error is in stdout.

Test Plan:
Manually tested by failing the ansible tasks. Screenshots attached. Also tested by copying the tmp output files locally.

Before this fix:
{F313328}

With this fix:
{F313329}

Reviewers: amalyshev, cwang, nbhatia, muthu, svarshney

Reviewed By: svarshney

Subscribers: yugaware

Differential Revision: https://phorge.dev.yugabyte.com/D40310
  • Loading branch information
nkhogen committed Nov 27, 2024
1 parent 0647d47 commit 1d7147d
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 13 deletions.
1 change: 1 addition & 0 deletions managed/devops/opscli/ybops/cloud/common/ansible.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ def run(self, filename, extra_vars=None, host_info=None, print_output=True,
stdout_str = stdout.decode('utf-8')
stderr_str = stderr.decode('utf-8') if rc != 0 else ""
if print_output:
# Write output to stderr by default.
logging.info(stdout_str)

if rc != 0:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ public class ShellProcessHandler {

static final Pattern ANSIBLE_FAIL_PAT =
Pattern.compile(
"(ybops.common.exceptions.YBOpsRuntimeError: Runtime error: "
+ "Playbook run.* )with args.* (failed with.*? [0-9]+)");
"(ybops\\.common\\.exceptions\\.YB[^\\s]+Error:.*? Playbook run.*?)with args.* (failed"
+ " with.*? [0-9]+)");
static final Pattern ANSIBLE_FAILED_TASK_PAT =
Pattern.compile("TASK.*?fatal.*?FAILED.*", Pattern.DOTALL);
Pattern.compile("TASK\\s+\\[.+\\].*?(fatal:.*?FAILED.*|failed: (?!false).*)", Pattern.DOTALL);
static final Pattern PYTHON_ERROR_PAT =
Pattern.compile("(<yb-python-error>)(.*?)(</yb-python-error>)", Pattern.DOTALL);
static final String ANSIBLE_IGNORING = "ignoring";
Expand Down Expand Up @@ -178,11 +178,12 @@ public ShellResponse run(List<String> command, ShellProcessContext context) {
itse);
}
response.message = (response.code == ERROR_CODE_SUCCESS) ? processOutput : processError;
String specificErrMsg = getAnsibleErrMsg(response.code, processOutput, processError);
if (specificErrMsg == null) {
specificErrMsg = getPythonErrMsg(response.code, processOutput);
}
String specificErrMsg = getPythonErrMsg(response.code, processOutput);
if (specificErrMsg != null) {
String ansibleErrMsg = getAnsibleErrMsg(response.code, specificErrMsg, processError);
if (ansibleErrMsg != null) {
specificErrMsg = ansibleErrMsg;
}
response.message = specificErrMsg;
}
}
Expand Down Expand Up @@ -390,20 +391,21 @@ private static void destroyForcibly(Process process, String description) {
}
}

private static String getAnsibleErrMsg(int code, String stdout, String stderr) {
private static String getAnsibleErrMsg(int code, String pythonErrMsg, String stderr) {

if (stderr == null || code == ERROR_CODE_SUCCESS) return null;
if (pythonErrMsg == null || stderr == null || code == ERROR_CODE_SUCCESS) return null;

String result = null;

Matcher ansibleFailMatch = ANSIBLE_FAIL_PAT.matcher(stderr);
Matcher ansibleFailMatch = ANSIBLE_FAIL_PAT.matcher(pythonErrMsg);
if (ansibleFailMatch.find()) {
result = ansibleFailMatch.group(1) + ansibleFailMatch.group(2);

// Attempt to find a line in ansible stdout for the failed task.
// By default, python logging module writes to stderr.
// Attempt to find a line in ansible stderr for the failed task.
// Logs for each task are separated by empty lines.
// Some fatal failures are ignored by ansible, so skip them
for (String s : stdout.split("\\R\\R")) {
// Some fatal failures are ignored by ansible, so skip them.
for (String s : stderr.split("\\R\\R")) {
if (s.contains(ANSIBLE_IGNORING)) {
continue;
}
Expand Down

0 comments on commit 1d7147d

Please sign in to comment.