如何预期 Ansible 任务失败?

How to expect failure from Ansible task?

我的一个 Ansible 任务经常失败,我遇到了问题。但是,问题不在于任务失败(我预计它会失败),但我想做的是即使它失败了也将其显示为成功。

我之所以要这样做,是因为任务是 运行 使用 WinRM 在 Windows 服务器上安装 Powershell 脚本,并且 Powershell 脚本正在为 WinRM 启用证书身份验证。当在 Windows 服务器上重置 WinRM 服务时,这会导致与服务器的 WinRM 连接中止。因此,当应用这些对 WinRM 的更改时,任务将失败。

任务失败的事实很好,因为剧本中的下一个任务是检查 WinRM 的更改是否已成功应用。因此,任务是 运行,参数为“ignore_errors: yes”。但是,我想将任务显示为成功,即使它失败了。我尝试设置参数“failed_when: false”(任务应该总是成功的)和“no_log: true”,但这似乎对任务没有任何影响,它仍然给出以下输出:

fatal: [X.X.X.X]: FAILED! => {"censored": "the output has been hidden due to the fact that 'no_log: true' was specified for this result"}

完整的任务如下所示:

- name: Activate certificate authentication for WinRM on server
  ansible.windows.win_powershell:
    script: |
      {{ remote_working_dir }}\ConfigureWinRMCertificateAuthentication.ps1
  ignore_errors: yes
  failed_when: false
  no_log: true

在执行此任务之前,Powershell 脚本“ConfigureWinRMCertificateAuthentication.ps1”已在 {{ remote_working_dir }} 中上传到服务器。 Powershell 脚本简单地配置 CA 证书、用户证书和服务器证书以供 WinRM 服务使用,使用新证书创建一个新的 WSMan 实例,然后为 WinRM 启用基于证书的身份验证。

当任务是运行没有“no_log:true”时的错误是:

requests.exceptions.ConnectionError: ('Connection aborted.', OSError("(104, 'ECONNRESET')"))
fatal: [172.27.25.37]: FAILED! => {
    "msg": "Unexpected failure during module execution.",
    "stdout": ""

长话短说: 因此我想问的问题是,有没有什么办法可以显示任务执行过程中连接中止的任务成功?

编辑:

添加任务注册结果的输出:

    ok: [X.X.X.X] => {
    "changed": false,
    "msg": {
        "exception": "Traceback (most recent call last):\n  File \"/usr/lib/python3/dist-packages/urllib3/connectionpool.py\", line 665, in urlopen\n    httplib_response = self._make_request(\n  File \"/usr/lib/python3/dist-packages/urllib3/connectionpool.py\", line 421, in _make_request\n    six.raise_from(e, None)\n  File \"<string>\", line 3, in raise_from\n  File \"/usr/lib/python3/dist-packages/urllib3/connectionpool.py\", line 416, in _make_request\n    httplib_response = conn.getresponse()\n  File \"/usr/lib/python3.8/http/client.py\", line 1348, in getresponse\n    response.begin()\n  File \"/usr/lib/python3.8/http/client.py\", line 316, in begin\n    version, status, reason = self._read_status()\n  File \"/usr/lib/python3.8/http/client.py\", line 277, in _read_status\n    line = str(self.fp.readline(_MAXLINE + 1), \"iso-8859-1\")\n  File \"/usr/lib/python3.8/socket.py\", line 669, in readinto\n    return self._sock.recv_into(b)\n  File \"/usr/lib/python3/dist-packages/urllib3/contrib/pyopenssl.py\", line 328, in recv_into\n    return self.recv_into(*args, **kwargs)\n  File \"/usr/lib/python3/dist-packages/urllib3/contrib/pyopenssl.py\", line 318, in recv_into\n    raise SocketError(str(e))\nOSError: (104, 'ECONNRESET')\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n  File \"/usr/lib/python3/dist-packages/requests/adapters.py\", line 439, in send\n    resp = conn.urlopen(\n  File \"/usr/lib/python3/dist-packages/urllib3/connectionpool.py\", line 719, in urlopen\n    retries = retries.increment(\n  File \"/usr/lib/python3/dist-packages/urllib3/util/retry.py\", line 400, in increment\n    raise six.reraise(type(error), error, _stacktrace)\n  File \"/usr/lib/python3/dist-packages/six.py\", line 702, in reraise\n    raise value.with_traceback(tb)\n  File \"/usr/lib/python3/dist-packages/urllib3/connectionpool.py\", line 665, in urlopen\n    httplib_response = self._make_request(\n  File \"/usr/lib/python3/dist-packages/urllib3/connectionpool.py\", line 421, in _make_request\n    six.raise_from(e, None)\n  File \"<string>\", line 3, in raise_from\n  File \"/usr/lib/python3/dist-packages/urllib3/connectionpool.py\", line 416, in _make_request\n    httplib_response = conn.getresponse()\n  File \"/usr/lib/python3.8/http/client.py\", line 1348, in getresponse\n    response.begin()\n  File \"/usr/lib/python3.8/http/client.py\", line 316, in begin\n    version, status, reason = self._read_status()\n  File \"/usr/lib/python3.8/http/client.py\", line 277, in _read_status\n    line = str(self.fp.readline(_MAXLINE + 1), \"iso-8859-1\")\n  File \"/usr/lib/python3.8/socket.py\", line 669, in readinto\n    return self._sock.recv_into(b)\n  File \"/usr/lib/python3/dist-packages/urllib3/contrib/pyopenssl.py\", line 328, in recv_into\n    return self.recv_into(*args, **kwargs)\n  File \"/usr/lib/python3/dist-packages/urllib3/contrib/pyopenssl.py\", line 318, in recv_into\n    raise SocketError(str(e))\nurllib3.exceptions.ProtocolError: ('Connection aborted.', OSError(\"(104, 'ECONNRESET')\"))\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n  File \"/usr/lib/python3/dist-packages/ansible/executor/task_executor.py\", line 146, in run\n    res = self._execute()\n  File \"/usr/lib/python3/dist-packages/ansible/executor/task_executor.py\", line 645, in _execute\n    result = self._handler.run(task_vars=variables)\n  File \"/usr/lib/python3/dist-packages/ansible/plugins/action/normal.py\", line 46, in run\n    result = merge_hash(result, self._execute_module(task_vars=task_vars, wrap_async=wrap_async))\n  File \"/usr/lib/python3/dist-packages/ansible/plugins/action/__init__.py\", line 923, in _execute_module\n    res = self._low_level_execute_command(cmd, sudoable=sudoable, in_data=in_data)\n  File \"/usr/lib/python3/dist-packages/ansible/plugins/action/__init__.py\", line 1071, in _low_level_execute_command\n    rc, stdout, stderr = self._connection.exec_command(cmd, in_data=in_data, sudoable=sudoable)\n  File \"/usr/lib/python3/dist-packages/ansible/plugins/connection/winrm.py\", line 548, in exec_command\n    result = self._winrm_exec(cmd_parts[0], cmd_parts[1:], from_exec=True, stdin_iterator=stdin_iterator)\n  File \"/usr/lib/python3/dist-packages/ansible/plugins/connection/winrm.py\", line 475, in _winrm_exec\n    resptuple = self.protocol.get_command_output(self.shell_id, command_id)\n  File \"/usr/local/lib/python3.8/dist-packages/winrm/protocol.py\", line 449, in get_command_output\n    self._raw_get_command_output(shell_id, command_id)\n  File \"/usr/local/lib/python3.8/dist-packages/winrm/protocol.py\", line 468, in _raw_get_command_output\n    res = self.send_message(xmltodict.unparse(req))\n  File \"/usr/local/lib/python3.8/dist-packages/winrm/protocol.py\", line 243, in send_message\n    resp = self.transport.send_message(message)\n  File \"/usr/local/lib/python3.8/dist-packages/winrm/transport.py\", line 323, in send_message\n    response = self._send_message_request(prepared_request, message)\n  File \"/usr/local/lib/python3.8/dist-packages/winrm/transport.py\", line 328, in _send_message_request\n    response = self.session.send(prepared_request, timeout=self.read_timeout_sec)\n  File \"/usr/lib/python3/dist-packages/requests/sessions.py\", line 646, in send\n    r = adapter.send(request, **kwargs)\n  File \"/usr/lib/python3/dist-packages/requests/adapters.py\", line 498, in send\n    raise ConnectionError(err, request=request)\nrequests.exceptions.ConnectionError: ('Connection aborted.', OSError(\"(104, 'ECONNRESET')\"))\n",
        "failed": true,
        "msg": "Unexpected failure during module execution.",
        "stdout": ""
    }
}

编辑 2:

运行任务配置如下:

- name: Activate certificate authentication for WinRM on server
  ansible.windows.win_powershell:
    script: |
      {{ remote_working_dir }}\ConfigureWinRMCertificateAuthentication.ps1
  register: test
  ignore_errors: yes
  failed_when: rc != 0
  no_log: true

- name: Dump results
  ansible.builtin.debug:
    msg: "{{ test }}"

产生以下调试输出(和一个失败的任务):

   TASK [Dump results] *********************************************************************************************************************************************************************************************************************************************
    ok: [172.27.25.37] => {
        "changed": false,
        "msg": {
            "exception": "Traceback (most recent call last):\n  File \"/usr/lib/python3/dist-packages/urllib3/connectionpool.py\", line 665, in urlopen\n    httplib_response = self._make_request(\n  File \"/usr/lib/python3/dist-packages/urllib3/connectionpool.py\", line 421, in _make_request\n    six.raise_from(e, None)\n  File \"<string>\", line 3, in raise_from\n  File \"/usr/lib/python3/dist-packages/urllib3/connectionpool.py\", line 416, in _make_request\n    httplib_response = conn.getresponse()\n  File \"/usr/lib/python3.8/http/client.py\", line 1348, in getresponse\n    response.begin()\n  File \"/usr/lib/python3.8/http/client.py\", line 316, in begin\n    version, status, reason = self._read_status()\n  File \"/usr/lib/python3.8/http/client.py\", line 277, in _read_status\n    line = str(self.fp.readline(_MAXLINE + 1), \"iso-8859-1\")\n  File \"/usr/lib/python3.8/socket.py\", line 669, in readinto\n    return self._sock.recv_into(b)\n  File \"/usr/lib/python3/dist-packages/urllib3/contrib/pyopenssl.py\", line 328, in recv_into\n    return self.recv_into(*args, **kwargs)\n  File \"/usr/lib/python3/dist-packages/urllib3/contrib/pyopenssl.py\", line 318, in recv_into\n    raise SocketError(str(e))\nOSError: (104, 'ECONNRESET')\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n  File \"/usr/lib/python3/dist-packages/requests/adapters.py\", line 439, in send\n    resp = conn.urlopen(\n  File \"/usr/lib/python3/dist-packages/urllib3/connectionpool.py\", line 719, in urlopen\n    retries = retries.increment(\n  File \"/usr/lib/python3/dist-packages/urllib3/util/retry.py\", line 400, in increment\n    raise six.reraise(type(error), error, _stacktrace)\n  File \"/usr/lib/python3/dist-packages/six.py\", line 702, in reraise\n    raise value.with_traceback(tb)\n  File \"/usr/lib/python3/dist-packages/urllib3/connectionpool.py\", line 665, in urlopen\n    httplib_response = self._make_request(\n  File \"/usr/lib/python3/dist-packages/urllib3/connectionpool.py\", line 421, in _make_request\n    six.raise_from(e, None)\n  File \"<string>\", line 3, in raise_from\n  File \"/usr/lib/python3/dist-packages/urllib3/connectionpool.py\", line 416, in _make_request\n    httplib_response = conn.getresponse()\n  File \"/usr/lib/python3.8/http/client.py\", line 1348, in getresponse\n    response.begin()\n  File \"/usr/lib/python3.8/http/client.py\", line 316, in begin\n    version, status, reason = self._read_status()\n  File \"/usr/lib/python3.8/http/client.py\", line 277, in _read_status\n    line = str(self.fp.readline(_MAXLINE + 1), \"iso-8859-1\")\n  File \"/usr/lib/python3.8/socket.py\", line 669, in readinto\n    return self._sock.recv_into(b)\n  File \"/usr/lib/python3/dist-packages/urllib3/contrib/pyopenssl.py\", line 328, in recv_into\n    return self.recv_into(*args, **kwargs)\n  File \"/usr/lib/python3/dist-packages/urllib3/contrib/pyopenssl.py\", line 318, in recv_into\n    raise SocketError(str(e))\nurllib3.exceptions.ProtocolError: ('Connection aborted.', OSError(\"(104, 'ECONNRESET')\"))\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n  File \"/usr/lib/python3/dist-packages/ansible/executor/task_executor.py\", line 146, in run\n    res = self._execute()\n  File \"/usr/lib/python3/dist-packages/ansible/executor/task_executor.py\", line 645, in _execute\n    result = self._handler.run(task_vars=variables)\n  File \"/usr/lib/python3/dist-packages/ansible/plugins/action/normal.py\", line 46, in run\n    result = merge_hash(result, self._execute_module(task_vars=task_vars, wrap_async=wrap_async))\n  File \"/usr/lib/python3/dist-packages/ansible/plugins/action/__init__.py\", line 923, in _execute_module\n    res = self._low_level_execute_command(cmd, sudoable=sudoable, in_data=in_data)\n  File \"/usr/lib/python3/dist-packages/ansible/plugins/action/__init__.py\", line 1071, in _low_level_execute_command\n    rc, stdout, stderr = self._connection.exec_command(cmd, in_data=in_data, sudoable=sudoable)\n  File \"/usr/lib/python3/dist-packages/ansible/plugins/connection/winrm.py\", line 548, in exec_command\n    result = self._winrm_exec(cmd_parts[0], cmd_parts[1:], from_exec=True, stdin_iterator=stdin_iterator)\n  File \"/usr/lib/python3/dist-packages/ansible/plugins/connection/winrm.py\", line 475, in _winrm_exec\n    resptuple = self.protocol.get_command_output(self.shell_id, command_id)\n  File \"/usr/local/lib/python3.8/dist-packages/winrm/protocol.py\", line 449, in get_command_output\n    self._raw_get_command_output(shell_id, command_id)\n  File \"/usr/local/lib/python3.8/dist-packages/winrm/protocol.py\", line 468, in _raw_get_command_output\n    res = self.send_message(xmltodict.unparse(req))\n  File \"/usr/local/lib/python3.8/dist-packages/winrm/protocol.py\", line 243, in send_message\n    resp = self.transport.send_message(message)\n  File \"/usr/local/lib/python3.8/dist-packages/winrm/transport.py\", line 323, in send_message\n    response = self._send_message_request(prepared_request, message)\n  File \"/usr/local/lib/python3.8/dist-packages/winrm/transport.py\", line 328, in _send_message_request\n    response = self.session.send(prepared_request, timeout=self.read_timeout_sec)\n  File \"/usr/lib/python3/dist-packages/requests/sessions.py\", line 646, in send\n    r = adapter.send(request, **kwargs)\n  File \"/usr/lib/python3/dist-packages/requests/adapters.py\", line 498, in send\n    raise ConnectionError(err, request=request)\nrequests.exceptions.ConnectionError: ('Connection aborted.', OSError(\"(104, 'ECONNRESET')\"))\n",
            "failed": true,
            "msg": "Unexpected failure during module execution.",
            "stdout": ""
        }
    }

然后 运行使用以下配置执行任务:

- name: Activate certificate authentication for WinRM on server
      ansible.windows.win_powershell:
        script: |
          {{ remote_working_dir }}\ConfigureWinRMCertificateAuthentication.ps1
      register: test
      ignore_errors: yes
      failed_when: rc == 0
      no_log: true

    - name: Dump results
      ansible.builtin.debug:
        msg: "{{ test }}"

产生以下调试输出(也是一个失败的任务):

TASK [Dump results] *********************************************************************************************************************************************************************************************************************************************
ok: [172.27.25.37] => {
    "changed": false,
    "msg": {
        "exception": "Traceback (most recent call last):\n  File \"/usr/lib/python3/dist-packages/urllib3/connectionpool.py\", line 665, in urlopen\n    httplib_response = self._make_request(\n  File \"/usr/lib/python3/dist-packages/urllib3/connectionpool.py\", line 421, in _make_request\n    six.raise_from(e, None)\n  File \"<string>\", line 3, in raise_from\n  File \"/usr/lib/python3/dist-packages/urllib3/connectionpool.py\", line 416, in _make_request\n    httplib_response = conn.getresponse()\n  File \"/usr/lib/python3.8/http/client.py\", line 1348, in getresponse\n    response.begin()\n  File \"/usr/lib/python3.8/http/client.py\", line 316, in begin\n    version, status, reason = self._read_status()\n  File \"/usr/lib/python3.8/http/client.py\", line 277, in _read_status\n    line = str(self.fp.readline(_MAXLINE + 1), \"iso-8859-1\")\n  File \"/usr/lib/python3.8/socket.py\", line 669, in readinto\n    return self._sock.recv_into(b)\n  File \"/usr/lib/python3/dist-packages/urllib3/contrib/pyopenssl.py\", line 328, in recv_into\n    return self.recv_into(*args, **kwargs)\n  File \"/usr/lib/python3/dist-packages/urllib3/contrib/pyopenssl.py\", line 318, in recv_into\n    raise SocketError(str(e))\nOSError: (104, 'ECONNRESET')\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n  File \"/usr/lib/python3/dist-packages/requests/adapters.py\", line 439, in send\n    resp = conn.urlopen(\n  File \"/usr/lib/python3/dist-packages/urllib3/connectionpool.py\", line 719, in urlopen\n    retries = retries.increment(\n  File \"/usr/lib/python3/dist-packages/urllib3/util/retry.py\", line 400, in increment\n    raise six.reraise(type(error), error, _stacktrace)\n  File \"/usr/lib/python3/dist-packages/six.py\", line 702, in reraise\n    raise value.with_traceback(tb)\n  File \"/usr/lib/python3/dist-packages/urllib3/connectionpool.py\", line 665, in urlopen\n    httplib_response = self._make_request(\n  File \"/usr/lib/python3/dist-packages/urllib3/connectionpool.py\", line 421, in _make_request\n    six.raise_from(e, None)\n  File \"<string>\", line 3, in raise_from\n  File \"/usr/lib/python3/dist-packages/urllib3/connectionpool.py\", line 416, in _make_request\n    httplib_response = conn.getresponse()\n  File \"/usr/lib/python3.8/http/client.py\", line 1348, in getresponse\n    response.begin()\n  File \"/usr/lib/python3.8/http/client.py\", line 316, in begin\n    version, status, reason = self._read_status()\n  File \"/usr/lib/python3.8/http/client.py\", line 277, in _read_status\n    line = str(self.fp.readline(_MAXLINE + 1), \"iso-8859-1\")\n  File \"/usr/lib/python3.8/socket.py\", line 669, in readinto\n    return self._sock.recv_into(b)\n  File \"/usr/lib/python3/dist-packages/urllib3/contrib/pyopenssl.py\", line 328, in recv_into\n    return self.recv_into(*args, **kwargs)\n  File \"/usr/lib/python3/dist-packages/urllib3/contrib/pyopenssl.py\", line 318, in recv_into\n    raise SocketError(str(e))\nurllib3.exceptions.ProtocolError: ('Connection aborted.', OSError(\"(104, 'ECONNRESET')\"))\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n  File \"/usr/lib/python3/dist-packages/ansible/executor/task_executor.py\", line 146, in run\n    res = self._execute()\n  File \"/usr/lib/python3/dist-packages/ansible/executor/task_executor.py\", line 645, in _execute\n    result = self._handler.run(task_vars=variables)\n  File \"/usr/lib/python3/dist-packages/ansible/plugins/action/normal.py\", line 46, in run\n    result = merge_hash(result, self._execute_module(task_vars=task_vars, wrap_async=wrap_async))\n  File \"/usr/lib/python3/dist-packages/ansible/plugins/action/__init__.py\", line 923, in _execute_module\n    res = self._low_level_execute_command(cmd, sudoable=sudoable, in_data=in_data)\n  File \"/usr/lib/python3/dist-packages/ansible/plugins/action/__init__.py\", line 1071, in _low_level_execute_command\n    rc, stdout, stderr = self._connection.exec_command(cmd, in_data=in_data, sudoable=sudoable)\n  File \"/usr/lib/python3/dist-packages/ansible/plugins/connection/winrm.py\", line 548, in exec_command\n    result = self._winrm_exec(cmd_parts[0], cmd_parts[1:], from_exec=True, stdin_iterator=stdin_iterator)\n  File \"/usr/lib/python3/dist-packages/ansible/plugins/connection/winrm.py\", line 475, in _winrm_exec\n    resptuple = self.protocol.get_command_output(self.shell_id, command_id)\n  File \"/usr/local/lib/python3.8/dist-packages/winrm/protocol.py\", line 449, in get_command_output\n    self._raw_get_command_output(shell_id, command_id)\n  File \"/usr/local/lib/python3.8/dist-packages/winrm/protocol.py\", line 468, in _raw_get_command_output\n    res = self.send_message(xmltodict.unparse(req))\n  File \"/usr/local/lib/python3.8/dist-packages/winrm/protocol.py\", line 243, in send_message\n    resp = self.transport.send_message(message)\n  File \"/usr/local/lib/python3.8/dist-packages/winrm/transport.py\", line 323, in send_message\n    response = self._send_message_request(prepared_request, message)\n  File \"/usr/local/lib/python3.8/dist-packages/winrm/transport.py\", line 328, in _send_message_request\n    response = self.session.send(prepared_request, timeout=self.read_timeout_sec)\n  File \"/usr/lib/python3/dist-packages/requests/sessions.py\", line 646, in send\n    r = adapter.send(request, **kwargs)\n  File \"/usr/lib/python3/dist-packages/requests/adapters.py\", line 498, in send\n    raise ConnectionError(err, request=request)\nrequests.exceptions.ConnectionError: ('Connection aborted.', OSError(\"(104, 'ECONNRESET')\"))\n",
        "failed": true,
        "msg": "Unexpected failure during module execution.",
        "stdout": ""
    }
}

因此,更改 failed_when 参数(无论我将其设置为什么)似乎对任务结果没有影响。

使用寄存器和“.failed”。这是我自己的一个案例,我正在测试 kubernetes 部署未能按预期部署:

- name: Test webhook rejects with no label
  kubernetes.core.k8s:
    state: present
    namespace: "{{ webhook_namespace }}"
    definition: "{{ lookup('template', 'roles/gke-setup-tasks/files/nginx-test-webhook-no-label.yaml') | from_yaml }}"
  register: test
  failed_when: not test.failed

因此,如果 失败,我声明该任务被视为“失败”。也就是说,如果任务成功了(deployment deployed),那我就认为任务失败了。


为了回应评论中的更多查询,这里是另一个示例,您可以根据 rc(或 return 代码——在 Windows 上失败,我相信这也被称为批处理脚本中的错误级别)

我们从一个会失败的简单任务开始:

- name: Do something that fails
  shell:
    cmd: /usr/bin/false

这给了我们预期的错误:

TASK [appinstalls : Do something that fails] ***********************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": "/usr/bin/false", "delta": "0:00:00.012978", "end": "2022-01-20 14:45:51.400921", "msg": "non-zero return code", "rc": 1, "start": "2022-01-20 14:45:51.387943", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}

现在让我们添加一个寄存器并转储内容。我们必须添加 ignore_errors 以便继续执行

- name: Do something that fails
  shell:
    cmd: /usr/bin/false
  register: test
  ignore_errors: true

- debug:
    msg: "{{test}}"
TASK [appinstalls : Do something that fails] *************************************************************************************************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": "/usr/bin/false", "delta": "0:00:00.010801", "end": "2022-01-20 14:48:35.689258", "msg": "non-zero return code", "rc": 1, "start": "2022-01-20 14:48:35.678457", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring

TASK [appinstalls : debug] *******************************************************************************************************************************************
ok: [localhost] => {
    "msg": {
        "changed": true,
        "cmd": "/usr/bin/false",
        "delta": "0:00:00.010801",
        "end": "2022-01-20 14:48:35.689258",
        "failed": true,
        "msg": "non-zero return code",
        "rc": 1,
        "start": "2022-01-20 14:48:35.678457",
        "stderr": "",
        "stderr_lines": [],
        "stdout": "",
        "stdout_lines": []
    }
}

现在请注意这里的 rc1?让我们更改任务,以便仅当 rc0 时才使任务失败(即,如果 rc 或 return 代码为零,我们将其视为失败) .我们现在还删除了 ignore_errors

- name: Do something that fails
  shell:
    cmd: /usr/bin/false
  register: test
  failed_when: test.rc == 0

- debug:
    msg: "{{test}}"

现在当我们 运行 它时,它不会失败,即使任务中的命令实际上失败了。

TASK [appinstalls : Do something that fails] *************************************************************************************************************************
changed: [localhost]

TASK [appinstalls : debug] *******************************************************************************************************************************************
ok: [localhost] => {
    "msg": {
        "changed": true,
        "cmd": "/usr/bin/false",
        "delta": "0:00:00.006484",
        "end": "2022-01-20 14:52:01.010044",
        "failed": false,
        "failed_when_result": false,
        "msg": "non-zero return code",
        "rc": 1,
        "start": "2022-01-20 14:52:01.003560",
        "stderr": "",
        "stderr_lines": [],
        "stdout": "",
        "stdout_lines": []
    }
}

那么如果我们做同样的事情,但使用实际成功的命令会发生什么:

- name: Do something that succeeds
  shell:
    cmd: echo "This is a success"
  register: test
  failed_when: test.rc == 0

- debug:
    msg: "{{test}}"

TASK [appinstalls : Do something that succeeds] **********************************************************************************************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": "echo \"This is a success\"", "delta": "0:00:00.005851", "end": "2022-01-20 14:54:46.082148", "failed_when_result": true, "msg": "", "rc": 0, "start": "2022-01-20 14:54:46.076297", "stderr": "", "stderr_lines": [], "stdout": "This is a success", "stdout_lines": ["This is a success"]}

因此,使用 rcfailed 属性将允许您覆盖或更改 Ansible 评估任务结果的内容。

执行中断连接的任务的正常解决方法是在 fire-and-forget 模式下使用 async。在实施 reboot 操作之前,这种模式过去经常用于服务器重启。

- name: Activate certificate authentication for WinRM on server
  ansible.windows.win_powershell:
    script: |
      Start-Sleep -s 2
      {{ remote_working_dir }}\ConfigureWinRMCertificateAuthentication.ps1
  async: 60
  poll: 0

脚本开头添加的睡眠确保在连接中断之前有时间将初始异步状态返回给 Ansible 控制器; async: 60 以 60 秒超时异步运行任务,poll: 0 告诉 Ansible 立即继续执行下一个任务。

这后面通常跟

- name: Wait for the server to come back
  wait_for_connection:
    delay: 30
    timeout: 300

优雅地重试连接,直到服务器再次可访问。