Ansible 交互式输入
输入普通信息
Ansible 支持在执行 Playbook 前手动输入变量值来设置变量。
- name: test prompt
hosts: all
become: true
gather_facts: false
vars_prompt:
- name: username
prompt: "Please enter username!"
private: false
default: "redhat"
- name: password
prompt: "Please enter password!"
tasks:
- name: print
ansible.builtin.debug:
msg: "Username is {{ username }}, Password is {{ password }}!"
vars_prompt默认情况下隐藏输入,通过private: false来设置显示输入内容。
default用于设置默认值。
输入密码信息
需要安装 Python 库 passlib。
[root@remote-host ansible]# pip3 install passlib
Collecting passlib
Downloading passlib-1.7.4-py2.py3-none-any.whl.metadata (1.7 kB)
Downloading passlib-1.7.4-py2.py3-none-any.whl (525 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 525.6/525.6 kB 171.3 kB/s eta 0:00:00
Installing collected packages: passlib
Successfully installed passlib-1.7.4
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager, possibly rendering your system unusable. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv. Use the --root-user-action option if you know what you are doing and want to suppress this warning.
安装 passlib 库后有以下加密方案可选:
| 加密算法名称 | 说明 |
|---|---|
bcrypt |
BCrypt 加密,现代强加密算法,安全性高,广泛推荐使用 |
sha512_crypt |
SHA-512 加密,与 Linux 系统 /etc/shadow 兼容 |
sha256_crypt |
SHA-256 加密,sha512_crypt 的简短版本 |
pbkdf2_digest |
通用 PBKDF2 哈希,可配置散列函数与迭代次数 |
phpass |
PHPass 的便携式哈希,用于 WordPress、phpBB 等 |
apr_md5_crypt |
Apache 的 MD5-Crypt 变体,适用于 .htpasswd |
scram |
SCRAM 哈希,用于 LDAP、SASL 等协议认证 |
sha1_crypt |
SHA-1 加密,已被视为弱加密,不推荐新项目使用 |
md5_crypt |
MD5 加密,旧版 Linux 系统中常见,已不安全 |
sun_md5_crypt |
Sun MD5 加密,Solaris 系统使用的变体 |
cta_pbkdf2_sha1 |
Cryptacular 的 PBKDF2 哈希 |
dlitz_pbkdf2_sha1 |
Dwayne Litzenberger 的 PBKDF2 哈希实现 |
bsd_nthash |
FreeBSD 的 MCF 兼容 nthash 编码,用于 NT 系统兼容场景 |
bsdi_crypt |
BSDi 加密,旧 BSD 系统使用,已过时 |
bigcrypt |
BigCrypt 加密,扩展的 DES 算法,较旧 |
crypt16 |
Crypt16 加密,早期 UNIX 加密方式,已废弃 |
des_crypt |
DES 加密,传统 Unix 算法,仅支持 8 位密码,非常不安全 |
如果没安装
passlib,会使用crypt库,只支持bcrypt、md5_crypt、sha256_crypt和sha512_crypt。
通过 vars_prompt 设置密码变量可用的参数:
| 参数名 | 示例值 | 说明 |
|---|---|---|
private |
false |
是否隐藏输入内容。默认为 true 可隐藏用户输入(适用于密码) |
encrypt |
sha512_crypt |
启用加密时,指定加密算法(如 sha512_crypt) |
confirm |
true |
要求用户重复输入以确认一致性,默认为 false |
salt_size |
8 |
自动生成随机盐的长度(单位:字节),如 salt_size: 16。和 salt 互斥 |
salt |
CZtwbq |
手动指定固定盐值(字符串),用于产生确定性加密结果,和 salt_size 互斥 |
示例:
[root@remote-host ansible]# cat test.yml
- name: test prompt
hosts: localhost
vars_prompt:
- name: username
prompt: Enter username
private: false
default: redhat
- name: password
prompt: Enter password
private: true
encrypt: sha512_crypt
confirm: true
salt_size: 7
tasks:
- name: print
ansible.builtin.debug:
msg: "Username is {{ username }}, Password is {{ password }}!"
[root@remote-host ansible]# ansible-playbook test.yml
Enter username [redhat]: root
Enter password:
confirm Enter password:
PLAY [test prompt] *****************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************
ok: [localhost]
TASK [print] ***********************************************************************************************************
ok: [localhost] => {
"msg": "Username is root, Password is $6$rounds=656000$Ygvov.3$EqqBEqq6RQgebiG7qoCtuxJv8973MPJwH.QFrUPCDZTmURIq5GaoNQrSTr0ro5QKSWvRh/./g4YjuqDNUp/TI0!"
}
PLAY RECAP *************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
接受特殊字符
如果想要输入一些特殊字符,比如:{、%。会有报错,报错信息如下:
[root@remote-host ansible]# ansible-playbook test.yml
Enter var1: {% 123 %}
Enter var2: {% 123 %}
PLAY [test prompt] *****************************************************************************************************
TASK [print] ***********************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "An unhandled exception occurred while templating '{% 123 %}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: template error while templating string: tag name expected. String: {% 123 %}. tag name expected"}
PLAY RECAP *************************************************************************************************************
localhost : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
这时就需要 unsafe: true,设置这个可以允许输入特殊字符,看下边:
[root@remote-host ansible]# cat test.yml
- name: test prompt
hosts: localhost
gather_facts: false
vars_prompt:
- name: var1
prompt: Enter var1
private: false
- name: var2
prompt: Enter var2
private: false
unsafe: true
tasks:
- name: print
ansible.builtin.debug:
msg: "var1 is {{ var1 }}, var2 is {{ var2 }}!"
[root@remote-host ansible]# ansible-playbook test.yml
Enter var1: {% 123 %}
Enter var2: {% 123 %}
PLAY [test prompt] *****************************************************************************************************
TASK [print] ***********************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "An unhandled exception occurred while templating '{% 123 %}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: template error while templating string: tag name expected. String: {% 123 %}. tag name expected"}
PLAY RECAP *************************************************************************************************************
localhost : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
[root@remote-host ansible]# ansible-playbook test.yml
Enter var1: 123
Enter var2: {% 123 %}
PLAY [test prompt] *****************************************************************************************************
TASK [print] ***********************************************************************************************************
ok: [localhost] => {
"msg": "var1 is 123, var2 is {% 123 %}!"
}
PLAY RECAP *************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Ansible 定义任务 changed 状态触发条件
默认情况下,Play 在对被控节点作出修改后就会处于 changed 状态。但有时也会有特殊情况:通过 ansible.builtin.command 模块在被控节点查询信息,查询信息不会对系统做出修改,但是 Ansible 默认会将 ansible.builtin.command 标记为 changed。
changed_when: false 将任务永久标记为 ok 状态(无论任务是否处于 changed 状态)。
- name: Print Hello World!
ansible.builtin.command: "echo 'Hello World!'"
changed_when: false
Ansible Playbook 条件判断
判断组合
Playbook 使用 when 关键字做判断,支持多个判断条件组合。
- name: playbook when
hosts: localhost
tasks:
- name: print hostvars
ansible.builtin.debug:
var: hostvars
- name: print ansible_facts
ansible.builtin.debug:
var: ansible_facts
- name: Run command on RedHat System
ansible.builtin.debug:
msg: "RedHat"
when: ansible_facts.os_family == 'RedHat'
- name: Run command on RedHat 8 System or RedHat 9 System
ansible.builtin.debug:
msg: "RedHat"
when: (ansible_facts.os_family == 'RedHat' and ansible_facts['distribution_major_version'] == '8') or
(ansible_facts.os_family == 'RedHat' and ansible_facts['distribution_major_version'] == '9')
根据任务状态判断
- name: test tasks status
hosts: localhost
gather_facts: false
tasks:
- name: Register a variable, ignore errors and continue
ansible.builtin.command: /bin/false
register: result
ignore_errors: true
- name: Run only if the task that registered the "result" variable fails
ansible.builtin.debug:
msg: 'command fail!'
when: result is failed
- name: Run only if the task that registered the "result" variable succeeds
ansible.builtin.debug:
msg: 'command success!'
when: result is succeeded
- name: Run only if the task that registered the "result" variable is skipped
ansible.builtin.debug:
msg: 'command skip!'
when: result is skipped
- name: Run only if the task that registered the "result" variable changed something.
ansible.builtin.debug:
msg: 'command change!'
when: result is changed
变量判断
判断变量布尔值(变量如果是字符串表示为 true),是否存在。
- name: test var
hosts: localhost
gather_facts: false
vars:
var1: true
var2: 'yes'
var3: 'no'
var4: no
tasks:
- name: if var1 or var2 is true, print one
ansible.builtin.debug:
msg: 'one'
when: var1 or var2 | bool
- name: if var3 is false, print two
ansible.builtin.debug:
msg: 'two'
when: not var3
- name: if var4 false, print three
ansible.builtin.debug:
msg: 'three'
when: not var4
- name: if var5 is undefined, print four
ansible.builtin.debug:
msg: 'four'
when: var5 is undefined
在变量不存在时跳过任务:
- name: test var with loop
hosts: localhost
gather_facts: false
tasks:
- name: Run with items greater than 5
ansible.builtin.debug:
msg: "{{ item }}"
loop: [ 0, 1, 4, 5, 7, 8, 9]
when: item > 5
- name: Skip the whole task when a loop variable is undefined
ansible.builtin.debug:
msg: "{{ item }}"
loop: "{{ mylist | default([]) }}"
when: item > 3
- name: The same as above using a dict
ansible.builtin.debug:
msg: "{{ item }}"
loop: "{{ query('dict', mydict|default({})) }}"
when: item.value > 5