金鱼哥说Ansible:第五章 实施任务控制---条件任务

举报
金鱼哥 发表于 2022/04/11 17:16:02 2022/04/11
【摘要】 玩转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的条件语句有两种写法:

  1. 将变量作为条件任务的触发器,使用True/False控制条件的触发。

  2. 在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语句的语法编写。

以上就是【金鱼哥】对 第五章 实施任务控制–条件任务 的简述和讲解。希望能对看到此文章的小伙伴有所帮助。

如果这篇【文章】有帮助到你,希望可以给【金鱼哥】点个赞👍,创作不易,相比官方的陈述,我更喜欢用【通俗易懂】的文笔去讲解每一个知识点,如果有对【运维技术】感兴趣,也欢迎关注❤️❤️❤️ 【金鱼哥】❤️❤️❤️,我将会给你带来巨大的【收获与惊喜】💕💕!

111

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。