如何强制 Ansible‘shell’任务使用‘changed_when’条件改变状态?

如何强制 Ansible‘shell’任务使用‘changed_when’条件改变状态?

我正在使用 Ansible 任务运行脚本,该脚本安装了一些存储库,我的目标是在运行更改模式时显示更改的状态以通知,如果检查模式未激活,则该脚本将运行。

我的第一个任务是检查这个存储库是否存在:

- name: Check repository existence
  become: yes
  shell: yum repolist -v | grep some-repository
  register: repo_exists
  check_mode: false
  failed_when: false
  changed_when: false

此任务应在检查模式下运行,以便我可以使用repo_exists变量在下一个任务中。当我在检查模式下运行 Ansible 时,这可以正常工作,这是输出:

"msg": {
    "changed": false,
    "cmd": "yum repolist -v | grep some-repository",
    "delta": "0:00:02.022965",
    "end": "2023-06-12 13:06:54.611504",
    "failed": false,
    "failed_when_result": false,
    "msg": "non-zero return code",
    "rc": 1,
    "start": "2023-06-12 13:06:52.588539",
    "stderr": "",
    "stderr_lines": [],
    "stdout": "",
    "stdout_lines": []
}

我的脚本应仅在存储库丢失时运行:

- name: Add repository
  become: yes
  shell: echo "install repository"
  changed_when: "repo_exists.rc != 0"
  when: "repo_exists.rc != 0"

when条件应确保,任务仅在以下情况下运行:rc不是零,这意味着存储库不在 repolist 中。 changed_when应该显示状态已改变即使在检查模式下rc不为零。

除了预期的结果,我可以看到状态跳过

{
  "changed": false,
  "cmd": "echo \"install repository\"",
  "delta": null,
  "end": null,
  "msg": "Command would have run if not in check mode",
  "rc": 0,
  "start": null,
  "stderr": "",
  "stderr_lines": [],
  "stdout": "",
  "stdout_lines": []
}

我不明白,为什么任务处于跳过状态以及我做错了什么?这是在运行检查模式时查看更改状态的 shell 任务的正确方法吗?

答案1

我不明白为什么任务处于跳过状态

正如前面提到的返回值

"msg": "Command would have run if not in check mode"

因为你是使用检查模式. 如果你真的想防止任务检查模式你需要使用

---
- hosts: localhost
  become: false
  gather_facts: false

  tasks:

  - name: Check repository existence
    shell:
      cmd: yum repolist -v | grep not-existing
    register: repo_exists
    # Since it is a reporting task
    # which needs to deliver a result in any case
    failed_when: repo_exists.rc != 0 and repo_exists.rc != 1
    changed_when: false
    check_mode: false

  - name: Add repository
    shell:
      cmd: "echo {{ repo_exists.stdout_lines }}"
    when: repo_exists.rc != 0
    changed_when: repo_exists.rc != 0
    check_mode: false
ansible-playbook main.yml --check -v

输出结果为

TASK [Check repository existence] ************
ok: [localhost] => changed=false
  cmd: yum repolist -v | grep not-existing
  delta: '0:00:05.598043'
  end: '2023-06-13 18:00:31.862501'
  failed_when_result: false
  msg: non-zero return code
  rc: 1
  start: '2023-06-13 18:00:26.264458'
  stderr: ''
  stderr_lines: <omitted>
  stdout: ''
  stdout_lines: <omitted>

TASK [Add repository] ************************
changed: [localhost] => changed=true
  cmd: echo []
  delta: '0:00:00.014928'
  end: '2023-06-13 18:00:32.318558'
  msg: ''
  rc: 0
  start: '2023-06-13 18:00:32.303630'
  stderr: ''
  stderr_lines: <omitted>
  stdout: '[]'
  stdout_lines: <omitted>

PLAY RECAP ***********************************
localhost                  : ok=2    changed=1

但请记住,这不再是shell模块的试运行。


每次都会运行它 - 不是必需的。我的目标是显示脚本是否会超出检查模式 - 因此将显示更改状态。

您所要求的是,shell命令或脚本本身首先需要知道它是否在运行check_mode: true,其次如果在运行,则其行为会有所不同。换句话说,您的脚本需要支持check_mode。这是shell模块正在做的事情部分,它不能代表或执行您的命令和脚本。

也许我理解错了,我定义的输出无法实现?

你至少需要实现类似

  - name: Add repository
    shell:
      cmd: "{{ ansible_check_mode | lower }} || echo {{ repo_exists.stdout_lines }}"
    changed_when: "repo_exists.rc != 0"
    when: repo_exists.rc != 0
    check_mode: false

使命令意识到check_mode,让它运行或不运行,并导致输出

TASK [Add repository] ***************
changed: [localhost] => changed=true
  cmd: true || echo []
  delta: '0:00:00.023104'
  end: '2023-06-15 11:00:00.550097'
  msg: ''
  rc: 0
  start: '2023-06-15 11:00:00.526993'
  stderr: ''
  stderr_lines: <omitted>
  stdout: ''
  stdout_lines: <omitted>

TASK [Add repository] ***************
changed: [localhost] => changed=true
  cmd: false || echo []
  delta: '0:00:00.014626'
  end: '2023-06-15 11:00:00.098413'
  msg: ''
  rc: 0
  start: '2023-06-15 11:00:00.083787'
  stderr: ''
  stderr_lines: <omitted>
  stdout: '[]'
  stdout_lines: <omitted>

由于这似乎已经变得非常复杂,你可能需要仔细考虑你真正想要实现的目标。X/Y问题并且已经有模块正在工作,只需添加一个存储库yum_repository模块 – 添加或删除 YUM 存储库与 f全部check_mode支持或更新ini_file模块 – 调整 INI 文件中的设置. 完全没有必要进行“检查添加如果仅当”或重新实现已经存在的功能。

相关内容