Ansible playbook 失败而不是运行救援块

问题描述 投票:0回答:1

我有以下 Ansible 剧本:

- hosts: <host>
  become: true
  vars:
    dest_dir: <dir>
  roles:
    - {role: '<role>', tags: '<tag>'}

被调用的

<role>
由单个任务文件组成:

- name: Copy and check file.
  block:
    - name: Copy
      ansible.builtin.copy:
        src: <source file>
        dest: "{{dest_dir}}"
        mode: 0666
        owner: root
        group: root
        backup: true
      register: copy_result
    - name: Print result
      ansible.builtin.debug:
        var: copy_result
    - name: Validate
      ansible.builtin.shell: <script> 1
      when: copy_result is changed
  rescue:
    - name: Revert
      ansible.builtin.copy:
        remote_src: true
        src: "{{copy_result.backup_file}}"
        dest: "{{dest_dir}}"
      when: copy_result.backup_file is defined

被调用的

<script>
是一个虚拟的,只是以与提供的参数匹配的退出代码退出:

exit $1

(此代码基于 Ansible 常见问题解答 https://docs.ansible.com/ansible/devel/reference_appendices/faq.html#the-validate-option-is-not-enough-for-my-needs -我做什么。

如果我在目标文件已经存在但与源文件内容不同时运行此命令,Ansible 会正确地将源文件复制到目标,并且我希望“验证”节会导致“救援”块,然后被调用,这应该“回滚”文件副本。 然而,“救援”块没有被调用;相反,剧本会从“验证”节中中止,并显示以下消息:

TASK [<task> : Validate] ******************************************************
fatal: [<host>]: FAILED! => {"changed": true, "cmd": "<script> 1", "delta": "0:00:00.010525", "end": "2024-09-17 10:49:23.559180", "msg": "non-zero return code", "rc": 1, "start": "2024-09-17 10:49:23.548655", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}

然后进入调试器。

我确实想知道“rescue”块的“when”参数是否有问题,但将其注释掉会导致相同的行为。

任何人都可以找出我在这里做错了什么吗?

ansible
1个回答
0
投票

首先,请注意

ansible.builtin.copy
模块有一个
validate
选项。使用它,您可以像这样重写您的剧本:

- hosts: localhost
  gather_facts: false
  vars:
    dest_dir: /tmp
  tasks:
  - name: Copy
    ansible.builtin.copy:
      src: testfile
      dest: "{{dest_dir}}/testfile"
      mode: 0666
      owner: root
      group: root
      backup: true
      validate: sh -c 'exit 1' %s

您可以用更少的代码有效地获得相同的行为。


关于您的问题,我无法重现您显示的错误。您没有在问题中提供,因此我制作了以下最小的、可重现的示例

- hosts: localhost
  gather_facts: false
  vars:
    dest_dir: /tmp
  tasks:
  - block:
      - name: Copy
        ansible.builtin.copy:
          src: testfile
          dest: "{{dest_dir}}"
          mode: 0666
          owner: root
          group: root
          backup: true
        register: copy_result

      - name: Print result
        ansible.builtin.debug:
          var: copy_result

      - name: Validate
        ansible.builtin.shell: "exit 1"
        when: copy_result is changed
    rescue:
      - name: Revert
        ansible.builtin.copy:
          remote_src: true
          src: "{{copy_result.backup_file}}"
          dest: "{{dest_dir}}"
        when: copy_result.backup_file is defined

运行此命令会产生(我使用

unixy
stdout 回调来减少输出):

- localhost on hosts: localhost -
Copy...
  localhost done
Print result...
  localhost ok: {
    "changed": false,
    "copy_result": {
        "backup_file": "/tmp/testfile.893626.2024-09-17@07:11:55~",
        "changed": true,
        "checksum": "22596363b3de40b06f981fb85d82312e8c0ed511",
        "dest": "/tmp/testfile",
        "diff": [],
        "failed": false,
        "gid": 0,
        "group": "root",
        "md5sum": "6f5902ac237024bdd0c176cb93063dc4",
        "mode": "0666",
        "owner": "root",
        "secontext": "unconfined_u:object_r:user_tmp_t:s0",
        "size": 12,
        "src": "/home/lars/.ansible/tmp/ansible-tmp-1726571514.9080791-893587-119392786896945/.source",
        "state": "file",
        "uid": 0
    }
}
Validate...
  localhost failed | msg: non-zero return code
Revert...
  localhost ok

- Play recap -
  localhost                  : ok=3    changed=1    unreachable=0    failed=0    rescued=1    ignored=0

我们可以清楚地看到“Revert”任务正在运行。但是,请注意“恢复”任务不会执行您想要的操作。在上面的例子中,我们的目标文件是

/tmp/testfile
,这意味着备份文件的名称类似于
/tmp/testfile.893626.2024-09-17@07:11:55~
。这使得“恢复”任务相当于:

- name: Revert
  ansible.builtin.copy:
    remote_src: true
    src: "/tmp/testfile.893626.2024-09-17@07:11:55~"
    dest: "/tmp"
  when: copy_result.backup_file is defined

这是一个禁止操作;您正在将备份文件复制到其自身上。如果要替换目标文件,则需要在

dest
参数中提供明确的文件名,而不是目录;这将使剧本看起来像这样:

- hosts: localhost
  gather_facts: false
  vars:
    dest_dir: /tmp
  tasks:
  - block:
      - name: Copy
        ansible.builtin.copy:
          src: testfile
          dest: "{{dest_dir}}/testfile"
          mode: 0666
          owner: root
          group: root
          backup: true
        register: copy_result

      - name: Print result
        ansible.builtin.debug:
          var: copy_result

      - name: Validate
        ansible.builtin.shell: "exit 1"
        when: copy_result is changed
    rescue:
      - name: Revert
        ansible.builtin.copy:
          remote_src: true
          src: "{{copy_result.backup_file}}"
          dest: "{{dest_dir}}/testfile"
        when: copy_result.backup_file is defined

当“验证”任务失败时,运行成功恢复文件。

© www.soinside.com 2019 - 2024. All rights reserved.