金鱼哥说Ansible:第五章 实施任务控制---条件任务
玩转Ansible条件任务而不踩坑
IT民工金鱼哥希望能以通俗易懂、诙谐幽默的方式把Ansible体系文章呈现给大家,让枯燥的知识点、让繁重的学习变的有趣一些。
前言
对于一些比较复杂的内容,例如在shell当中,我们会使用各种条件判断来进行,在Ansible当中也是,Ansible可使用conditionals,在符合特定条件时执行任务或play。例如,可以利用一个条件在Ansible安装或配置服务前确定受管主机上的可用内存。
我们可以利用条件来区分不同的受管主机,并根据它们所符合的条件来分配功能角色。Playbook变量、注册的变量和Ansible事实都可通过条件来进行测试。可以使用比较字符串、数字数据和布尔值的运算符。
以下场景说明了在Ansible中使用条件的情况:
- 可以在变量中定义硬限制(如min_memory)并将它与受管主机上的可用内存进行比较。
- Ansible可以捕获并评估命令的输出,以确定某一任务在执行进一步操作前是否已经完成。例如,如果某一程序失败,则将跳过批处理。
- 可以利用Ansible事实来确定受管主机网络配置,并决定要发送的模板文件(如,网络绑定或中继)。
- 可以评估CPU的数量,来确定如何正确调节某一Web服务器。
- 将注册的变量与预定义的变量进行比较,以确定服务是否已更改。例如,测试服务配置文件的MD5检验以和查看服务是否已更改。
1. 条件任务语法
when语句用于有条件地运行任务。它取要测试的条件为真。如果条件满足,则运行任务。如果条件不满足,则跳过任务。
简单的条件语句案例:
这个条件语句的意思是当my_server生效时才安装httpd;如果设置成False那么my_server并不生效
---
- name: when test
hosts: servera
remote_user: root
vars:
my_server: False
tasks:
- name: "{{ my_server }} is installed"
yum:
name: httpd
state: latest
when: my_server
测试可执行性:
[student@servera ~]$ ansible-playbook test.yml
PLAY [when test] ***********************************************************************************
TASK [Gathering Facts]******************************************************** ********************
ok: [servera]
TASK [False is installed] **************************************************************************
skipping: [servera]
PLAY RECAP ***************************************************************************************
servera : ok=1 changed=0 unreachable=0 failed=0
# 测试执行时直接跳过了。
这里跳过的原因是因为要安装httpd服务的条件是my_server变量必须存在,而将my_server设置成False后,my_server变量不生效就不满足when的条件,所以即使这个playbook语法有问题也可以执行,但其中包含的任务是不能被执行的所以直接跳过了。
如果将False改为True:
[student@workstation ~]$ ansible-playbook -i hosts test.yml
---
- name: when test
hosts: servera
remote_user: root
vars:
my_server: True
tasks:
- name: "{{ my_server }} is installed"
yum:
name: httpd
state: latest
when: my_server
执行测试
PLAY [when test] ************************************************************************
TASK [Gathering Facts] ******************************************************************
ok: [servera]
TASK [True is installed] ****************************************************************
changed: [servera]
PLAY RECAP ******************************************************************************
servera : ok=2 changed=1 unreachable=0 failed=0
# 此时的状态变成了changed而不是skipped
当状态变为changed证明任务状态已经发生改变,httpd服务已经符合了安装条件
另一种写法(defined):
---
- name: when test
hosts: servera
remote_user: root
tasks:
- name: "ensure {{ my_server }} is installed"
yum:
name: "{{ my_server }}"
state: latest
when: my_server is defined
需要注意的是,这里的my_server变量依旧是没有被定义的
[student@servera ~]$ ansible-playbook test.yml
PLAY [when test] ***********************************************************************************
TASK [Gathering Facts] ****************************************************************************
ok: [servera]
TASK [ensure {{ my_server }} is installed] *******************************************************
skipping: [servera]
PLAY RECAP **************************************************************************************
servera : ok=1 changed=0 unreachable=0 failed=0
# 所以在执行测试时也跳过了任务
如果定义my_server而不赋值:
[student@servera ~]$ cat test.yml
---
- name: when test
hosts: servera
remote_user: root
vars:
my_server:
tasks:
- name: "ensure {{ my_server }} is installed"
yum:
name: "{{ my_server }}"
state: latest
when: my_server is defined
# 这里的条件是如果变量my_server被定义则执行安装的任务
执行测试:
[student@servera ~]$ ansible-playbook test.yml
PLAY [when test] ************************************************************************
TASK [Gathering Facts] ******************************************************************
ok: [servera]
TASK [ensure is installed] *************************************************************
fatal: [servera]: FAILED! => {"changed": false, "module_stderr": "Shared connection to servera closed.\r\n", "module_stdout": "Traceback (most recent call last):\r\n File \"/root/.ansible/tmp/ansible-tmp-1599491486.79-25931710335605/AnsiballZ_yum.py\", line 113, in <module>\r\n _ansiballz_main()\r\n File \"/root/.ansible/tmp/ansible-tmp-1599491486.79-25931710335605/AnsiballZ_yum.py\", line 105, in _ansiballz_main\r\n invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\r\n File \"/root/.ansible/tmp/ansible-tmp-1599491486.79-25931710335605/AnsiballZ_yum.py\", line 48, in invoke_module\r\n imp.load_module('__main__', mod, module, MOD_DESC)\r\n File \"/tmp/ansible_yum_payload_FaoojI/__main__.py\", line 1532, in <module>\r\n File \"/tmp/ansible_yum_payload_FaoojI/__main__.py\", line 1527, in main\r\n File \"/tmp/ansible_yum_payload_FaoojI/__main__.py\", line 374, in __init__\r\n File \"/tmp/ansible_yum_payload_FaoojI/ansible_yum_payload.zip/ansible/module_utils/yumdnf.py\", line 79, in __init__\r\nTypeError: 'NoneType' object is not iterable\r\n", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}
to retry, use: --limit @/home/student/test.retry
PLAY RECAP ******************************************************************************
servera : ok=1 changed=0 unreachable=0 failed=1
# 在执行测试时会这样报错
如果定义的变量,却不给变量赋值。那么这个playbook是不能成功执行的,因为yum模块当中name是不能定义为空的。
如果我们给变量赋值:
---
- name: when test
hosts: servera
remote_user: root
vars:
my_server: httpd
tasks:
- name: "ensure {{ my_server }} is installed"
yum:
name: "{{ my_server }}"
state: latest
when: my_server is defined
# 这里指定my_server为httpd
测试执行:
[student@servera ~]$ ansible-playbook test.yml
PLAY [when test] ************************************************************************
TASK [Gathering Facts] ******************************************************************
ok: [servera]
TASK [ensure httpd is installed] ********************************************************
changed: [servera]
PLAY RECAP ******************************************************************************
servera : ok=2 changed=1 unreachable=0 failed=0
# 执行测试成功
如果这样编写playbook:
---
- name: when test
hosts: servera
remote_user: root
vars:
my_server:
tasks:
- name: "ensure httpd is installed"
yum:
name: httpd
state: latest
when: my_server is defined
这里的条件是如果my_server变量为被定义则执行安装httpd的任务。在条件语句中只要满足when的条件就执行任务。
然后也添加了vars,这样就相当于定义了my_server,只不过此时my_server的值为空,此时仍可以安装httpd服务即使my_server的值为空,因为空值也是有定义。
[student@servera ~]$ ansible-playbook -i hosts test.yml
PLAY [when test] ******************************************************************************
TASK [Gathering Facts] *************************************************************************
ok: [servera]
TASK [ensure httpd is installed] ***************************************************************
changed: [servera]
PLAY RECAP ***********************************************************************************
servera : ok=2 changed=1 unreachable=0 failed=0
2. 由此可以得知,when的条件语句有两种写法:
-
将变量作为条件任务的触发器,使用True/False控制条件的触发。
-
在playbook中定义变量并直接作为需要实施的任务,通过控制变量是否被定义(my_server is defined/my_server is not defined)来控制条件的触发。
下表显示了在处理条件时可使用的一些运算:
3. 示例条件语法
操作 | 示例 |
---|---|
等于(值为字符串 | ansible_machine == “x86_64” |
等于(值为数字) | max_memory == 512 |
小于 | min_memory < 128 |
大于 | min_memory > 256 |
小于等于 | min_memory <= 256 |
大于等于 | min_memory >= 512 |
不等于 | min_memory != 512 |
变量存在 | min_memory is defined |
变量不存在 | min_memory is not defined |
布尔变量是True。1、True或yes的求值为True | memory_available |
布尔变量是False。0、False或no的求值为False | not memory_available |
第一个变量的值存在,作为第二个变量的列表中的值 | ansible_distribution in supported_distros |
比较难理解应该是最后的那个语法,可参考以下剧本的演示来进行理解。
ansible_distribution in supported_distros类型的例子:
---
- name: when test
hosts: servera
remote_user: root
vars:
opreate_system:
- x86_64
- x86_32
tasks:
- name: httpd installed
yum:
name: httpd
state: present
when: ansible_facts['architecture'] in opreate_system
这里的条件语句意思是,如果ansible_facts中的ansible_architecture的值能在opreate_system变量中找到符合的值,则安装httpd服务,opreate_system是自己指定的变量
测试执行:
[student@servera ~]$ ansible-playbook -i hosts test.yml
PLAY [when test] ************************************************************************
TASK [Gathering Facts] ******************************************************************
ok: [servera]
TASK [httpd installed] ******************************************************************
changed: [servera]
PLAY RECAP ******************************************************************************
servera : ok=2 changed=1 unreachable=0 failed=0
注意when语句的缩进。由于when语句不是模块变量,它必须通过缩进到任务的最高级别,放置在模块的外面。
任务是YAML散列/字典,when语句只是任务中的又一个键,就如任务的名称以及它所使用的模块一样。通常的惯例是将可能存在的任何when关键字放在任务名称和模块(及模块参数)的后面。
总结
- 在一些复杂的调用,需要使用到条件任务来执行剧本任务。
- 条件任务需要判断条件为真才执行。
- 熟悉条件判断的各种语法。
- 注意when语句的语法编写。
以上就是【金鱼哥】对 第五章 实施任务控制–条件任务 的简述和讲解。希望能对看到此文章的小伙伴有所帮助。
如果这篇【文章】有帮助到你,希望可以给【金鱼哥】点个赞👍,创作不易,相比官方的陈述,我更喜欢用【通俗易懂】的文笔去讲解每一个知识点,如果有对【运维技术】感兴趣,也欢迎关注❤️❤️❤️ 【金鱼哥】❤️❤️❤️,我将会给你带来巨大的【收获与惊喜】💕💕!
- 点赞
- 收藏
- 关注作者
评论(0)