我有以下Ansible Playbook代码:
- name: Users | Generate password for user (Debian/Ubuntu)
shell: makepasswd --chars=20
register: make_password
when: ansible_distribution in ['Debian', 'Ubuntu']
- name: Users | Generate password for user (Fedora)
shell: makepasswd -m 20 -M 20
register: make_password
when: ansible_distribution in ['Fedora', 'Amazon']
- name: Users | Generate password for user (CentOS)
shell: mkpasswd -l 20
register: make_password
when: ansible_distribution in ['CentOS']
- name: debug
debug: var=make_password
哪个输出:
TASK: [users | debug]
ok: [127.0.0.1] => {
"var": {
"make_password": {
"changed": false,
"skipped": true
}
}
}
...因为无论register
条件如何,每个when
块都会被执行。
我如何解决此问题,以便在make_password
条件未满足时when
不会被覆盖?
或者如果这是你可以看到的我想要完成的错误方法,请告诉我一个更好的方法。
答案 0 :(得分:7)
不幸的是,这是预期的行为。来自Ansible Variables
注意强> 如果任务失败或被跳过,则仍会注册该变量 失败或跳过状态,唯一的方法是避免注册 变量使用标记。
我不知道如何使用标签来解决您的问题。
编辑:我发现了一种方法,尽管是一种粗糙的解决方案。存储结果,以免被覆盖 - set_fact: mypwd="{{make_password}}"
when: make_password.changed
所以你的代码看起来像是:
- name: Users | Generate password for user (Debian/Ubuntu)
shell: makepasswd --chars=20
register: make_password
when: ansible_distribution in ['Debian', 'Ubuntu']
- set_fact: mypwd="{{make_password}}"
when: make_password.changed
- name: Users | Generate password for user (Fedora)
shell: makepasswd -m 20 -M 20
register: make_password
when: ansible_distribution in ['Fedora', 'Amazon']
- set_fact: mypwd="{{make_password}}"
when: make_password.changed
- name: Users | Generate password for user (CentOS)
shell: mkpasswd -l 20
register: make_password
when: ansible_distribution in ['CentOS']
- set_fact: mypwd="{{make_password}}"
when: make_password.changed
- name: debug
debug: var=mypwd
答案 1 :(得分:3)
通常,对于在不同发行版上运行不同的任务,我倾向于包含一个特定于发行版的剧本,然后将其有条件地包含在main.yml中。
所以一个例子看起来像这样:
- include: tasks/Debian.yml
when: ansible_distribution in ['Debian', 'Ubuntu']
- include: tasks/Fedora.yml
when: ansible_distribution in ['Fedora', 'Amazon']
- include: tasks/Centos.yml
when: ansible_distribution in ['CentOS']
- name: debug
debug: var=make_password
- name: Users | Generate password for user (Debian/Ubuntu)
shell: makepasswd --chars=20
register: make_password
显然重复其他两个发行版。
这样你就可以让main.yml只运行可以在任何发行版上运行的角色的所有通用任务,但是那些需要不同的东西可以在一个特定于发行版的剧本中。因为include是有条件的,所以如果不满足条件,它甚至不会加载任务,因此不应该注册该变量。
答案 2 :(得分:2)
如何在var文件中定义一个dict?
make_password: {
'Debian':'makepasswd --chars=20',
'Ubuntu':'makepasswd --chars=20',
'Fedora':'makepasswd -m 20 -M 20',
'Amazon':'makepasswd -m 20 -M 20',
'CentOS':'mkpasswd -l 20'
}
---
- hosts: "{{ host }}"
remote_user: root
vars_files:
- vars.yml
tasks:
- name: get mkpasswd
debug: var="{{ make_password[ansible_distribution] }}"
运行结果:
TASK: [get mkpasswd]
ok: [10.10.10.1] => {
"mkpasswd -l 20": "mkpasswd -l 20"
}
答案 3 :(得分:-1)
将所有变体放入shell脚本然后运行该脚本而不是多个Ansible任务可能是有意义的。
脚本可以检测操作系统或只是对传递的参数做出反应。
#!/bin/bash
case "$1" in
"Debian" | "Ubuntu")
makepasswd --chars=20
;;
"Fedora" | "Amazon")
makepasswd -m 20 -M 20
;;
"CentOS")
mkpasswd -l 20
;;
*)
echo "Unexpected distribution" 1>&2
exit 1
;;
esac
将此内容放在角色的脚本文件夹make_password.sh
中,然后将其命名为:
- name: Users | Generate password for user
script: make_password.sh {{ ansible_distribution }}
register: make_password
另一个想法:您似乎实际上是远程生成密码,注册输出,然后在其他任务中使用它。如果您可以保证Ansible主主机始终属于同一类型,并且并非每个团队成员都使用不同的分发,则只需在本地运行该任务即可。
假设你使用Ubuntu:
- name: Users | Generate password for user
shell: makepasswd --chars=20
delegate_to: localhost
register: make_password
任务在您通过delegate_to
运行Ansible的主机上本地执行。