实施任务控制

1. 循环语句

1.1 简单循环

  • 示例:现需要将受控机的postfix和crond两个服务开启,我们在主控机利用循环变量item和loop模块将两个任务合成一个任务
  1. 先把受控机的两个服务关闭
[root@localhost facts.d]# systemctl stop postfix
[root@localhost facts.d]# systemctl status postfix
● postfix.service - Postfix Mail Transport Agent
   Loaded: loaded (/usr/lib/systemd/system/postfix.se>
   Active: inactive (dead)
[root@localhost facts.d]# systemctl stop crond
[root@localhost facts.d]# systemctl status crond
● crond.service - Command Scheduler
   Loaded: loaded (/usr/lib/systemd/system/crond.serv>
   Active: inactive (dead) since Sun 2020-09-06 21:48>
  Process: 8157 ExecStart=/usr/sbin/crond -n $CRONDAR>
 Main PID: 8157 (code=exited, status=0/SUCCESS)

Sep 06 21:36:23 localhost.localdomain systemd[1]: Sta>
Sep 06 21:36:23 localhost.localdomain crond[8157]: (C>
Sep 06 21:36:23 localhost.localdomain crond[8157]: (C>
Sep 06 21:36:23 localhost.localdomain crond[8157]: (C>
Sep 06 21:36:23 localhost.localdomain crond[8157]: (C>
Sep 06 21:48:45 localhost.localdomain systemd[1]: Sto>
Sep 06 21:48:45 localhost.localdomain systemd[1]: Sto>
lines 1-13/13 (END)
  1. 在主控机中编写
[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  tasks:
    - name: kk
      service:
        name: "{{ item }}"
        state: started
      loop:
        - postfix
        - crond

  1. 检查语法是否错误并执行playbook
[root@localhost playbook]# ansible-playbook --syntax-check myplay.yml 

playbook: myplay.yml
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [kk] **********************************************************************
changed: [192.168.50.136] => (item=postfix)
changed: [192.168.50.136] => (item=crond)

PLAY RECAP *********************************************************************
192.168.50.136             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
  1. 查看受控机的两个服务是否开启
[root@localhost facts.d]# systemctl status crond
● crond.service - Command Scheduler
   Loaded: loaded (/usr/lib/systemd/system/crond.serv>
   Active: active (running) since Sun 2020-09-06 21:5>
 Main PID: 8444 (crond)
......
[root@localhost facts.d]# systemctl status postfix
● postfix.service - Postfix Mail Transport Agent
   Loaded: loaded (/usr/lib/systemd/system/postfix.se>
   Active: active (running) since Sun 2020-09-06 21:3>
  Process: 8013 ExecStart=/usr/sbin/postfix start (co
......
  • 也可以把循环列表写到前面
  1. 查看受控机的两个服务状态(开启)
[root@localhost facts.d]# systemctl status crond
● crond.service - Command Scheduler
   Loaded: loaded (/usr/lib/systemd/system/crond.serv>
   Active: active (running) since Sun 2020-09-06 21:5>
[root@localhost facts.d]# systemctl status postfix
● postfix.service - Postfix Mail Transport Agent
   Loaded: loaded (/usr/lib/systemd/system/postfix.se>
   Active: active (running) since Sun 2020-09-06 21:3>
  1. 编写myplay.yml
[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  vars:
    srvs:
      - postfix        将这两个任务写在前面
      - crond
  tasks:
    - name: kk
      service:
        name: "{{ item }}"
        state: stopped
      loop: "{{ srvs }}"            srvs含有需要处于运行状态的服务的列表
  1. 查看受控机状态(关闭)
[root@localhost facts.d]# systemctl status postfix
● postfix.service - Postfix Mail Transport Agent
   Loaded: loaded (/usr/lib/systemd/system/postfix.se>
   Active: inactive (dead)

Sep 06 21:34:04 localhost.localdomain systemd[1]: Sta>
Sep 06 21:34:05 localhost.localdomain postfix/master[>
Sep 06 21:34:05 localhost.localdomain systemd[1]: Sta>
Sep 06 21:35:54 localhost.localdomain systemd[1]: Sto>
Sep 06 21:35:54 localhost.localdomain systemd[1]: Sto>
Sep 06 21:36:22 localhost.localdomain systemd[1]: Sta>
Sep 06 21:36:23 localhost.localdomain postfix/master[>
Sep 06 21:36:23 localhost.localdomain systemd[1]: Sta>
Sep 06 21:58:47 localhost.localdomain systemd[1]: Sto>
Sep 06 21:58:48 localhost.localdomain systemd[1]: Sto>
[root@localhost facts.d]# systemctl status crond
● crond.service - Command Scheduler
   Loaded: loaded (/usr/lib/systemd/system/crond.serv>
   Active: inactive (dead) since Sun 2020-09-06 21:58>
  Process: 8444 ExecStart=/usr/sbin/crond -n $CRONDAR>
 Main PID: 8444 (code=exited, status=0/SUCCESS)

1.2 循环散列或字典列表

示例: 在受控机上创建两个用户wangqing,houyi。wangqing属于apache组,houyi属于root组
1.在主控机上编写

[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  tasks:
    - name: kk
      user:
        name: "{{ item.name }}"
        state: present
        group: "{{ item.group }}"
      loop:
        - name: wangqing
          group: apache
        - name: houyi
          group: root

  1. 运行playbook
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [kk] **********************************************************************
changed: [192.168.50.136] => (item={'name': 'wangqing', 'group': 'apache'})
changed: [192.168.50.136] => (item={'name': 'houyi', 'group': 'root'})

PLAY RECAP *********************************************************************
192.168.50.136             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
  1. 受控机上查看两个用户
[root@localhost ~]# id wangqing
uid=1000(wangqing) gid=48(apache) groups=48(apache)
[root@localhost ~]# id houyi
uid=1001(houyi) gid=0(root) groups=0(root)

1.3 较早样式的循环关键字

较早样式的Ansible循环

循环关键字描述
with_items行为与简单列表的loop关键字相同,例如字符串列表或散列/字典列表。但与loop不同的是,如果为with_items提供了列表的列表,它们将被扁平化为单级列表。循环变量item保存每次迭代过程中使用的列表项。
with_file此关键字需要控制节点文件名列表。循环变量item在每次迭代过程中保存文件列表中相应文件的内容。
with_sequence此关键字不需要列表,而是需要参数来根据数字序列生成值列表。循环变量item在每次迭代过程中保存生成的序列中的一个生成项的值。

示例:

  1. 编写playbook
[root@localhost ~]# cd playbook/
[root@localhost playbook]# ls
!  myplay.yml
[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  vars:
    data:
      - 1
      - 2
      - 3
      - 4
      - 5
      - 6
  tasks:
    - name: pp
      debug:
        msg: "{{ item }}"                  item代表data中的每一项
      with_items: "{{ data }}"             with_items代表迭代谁,这里就迭代data
[root@localhost playbook]# ansible-playbook --syntax-check myplay.yml                          检查语法

playbook: myplay.yml
[root@localhost playbook]# ansible-playbook myplay.yml                            打印结果

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [pp] **********************************************************************
ok: [192.168.50.136] => (item=1) => {
    "msg": 1
}
ok: [192.168.50.136] => (item=2) => {
    "msg": 2
}
ok: [192.168.50.136] => (item=3) => {
    "msg": 3
}
ok: [192.168.50.136] => (item=4) => {
    "msg": 4
}
ok: [192.168.50.136] => (item=5) => {
    "msg": 5
}
ok: [192.168.50.136] => (item=6) => {
    "msg": 6
}

PLAY RECAP *********************************************************************
192.168.50.136             : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

1.4 将Register变量与Loop一起使用

示例: register关键字也可以捕获循环任务的输出。

[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  gather_facts: no                         关闭搜集功能
  tasks:
    - name: hh
      shell: "echo jjyy {{ item }}"
      loop:
        - yom
        - jerry
      register: result                        注册result这个结果里面去
    - name: show result
      debug:
        var: result
[root@localhost playbook]# ansible-playbook --syntax-check myplay.yml 

playbook: myplay.yml
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [hh] **********************************************************************
changed: [192.168.50.136] => (item=yom)
changed: [192.168.50.136] => (item=jerry)

TASK [show result] *************************************************************
ok: [192.168.50.136] => {
    "result": {
        "changed": true,
        "msg": "All items completed",
        "results": [
            {
                "ansible_facts": {
                    "discovered_interpreter_python": "/usr/libexec/platform-python"
                },
                "ansible_loop_var": "item",
                "changed": true,
                "cmd": "echo jjyy yom",
                "delta": "0:00:00.003770",
                "end": "2020-09-07 09:26:09.697735",
                "failed": false,
                "invocation": {
                    "module_args": {
                        "_raw_params": "echo jjyy yom",
                        "_uses_shell": true,
                        "argv": null,
                        "chdir": null,
                        "creates": null,
                        "executable": null,
                        "removes": null,
                        "stdin": null,
                        "stdin_add_newline": true,
                        "strip_empty_ends": true,
                        "warn": true
                    }
                },
                "item": "yom",
                "rc": 0,
                "start": "2020-09-07 09:26:09.693965",
                "stderr": "",
                "stderr_lines": [],
                "stdout": "jjyy yom",
                "stdout_lines": [
                    "jjyy yom"
                ]
            },
            {
                "ansible_loop_var": "item",
                "changed": true,
                "cmd": "echo jjyy jerry",
                "delta": "0:00:00.003909",
                "end": "2020-09-07 09:26:10.014186",
                "failed": false,
                "invocation": {
                    "module_args": {
                        "_raw_params": "echo jjyy jerry",
                        "_uses_shell": true,
                        "argv": null,
                        "chdir": null,
                        "creates": null,
                        "executable": null,
                        "removes": null,
                        "stdin": null,
                        "stdin_add_newline": true,
                        "strip_empty_ends": true,
                        "warn": true
                    }
                },
                "item": "jerry",
                "rc": 0,
                "start": "2020-09-07 09:26:10.010277",
                "stderr": "",
                "stderr_lines": [],
                "stdout": "jjyy jerry",
                "stdout_lines": [
                    "jjyy jerry"
                ]
            }
        ]
    }
}

PLAY RECAP *********************************************************************
192.168.50.136             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

2. 条件判断

以下场景说明了在Ansible中使用条件的情况:

  • 可以在变量中定义硬限制(如min_memory)并将它与受管主机上的可用内存进行比较。

  • Ansible可以捕获并评估命令的输出,以确定某一任务在执行进一步操作前是否已经完成。例如,如果某一程序失败,则将路过批处理。

*可以利用Ansible事实来确定受管主机网络配置,并决定要发送的模板文件(如,网络绑定或中继)。

  • 可以评估CPU的数量,来确定如何正确调节某一Web服务器。

  • 将注册的变量与预定义的变量进行比较,以确定服务是否已更改。例如,测试服务配置文件的MD5检验以和查看服务是否已更改。

2.1 语法

when语句用于有条件地运行任务。它取要测试的条件为值。如果条件满足,则运行任务。如果条件不满足,则跳过任务。

  • 示例: 现需要在受控机上安装阿帕奇。在写playbook时,my_condition为False,则直接跳过该任务,不会安装阿帕奇;若my_condition为True,则会安装阿帕奇
    1.编写playbook,my_condition为False
[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  vars:
    my_condition: False
  tasks:
    - name: 安装阿帕奇
      yum:
        name: httpd
        state: present
      when: my_condition          
  1. 查看受控机是否安装阿帕奇(没有安装)
[root@localhost ~]# rpm -qa|grep httpd
[root@localhost ~]# 
  1. 编写playbook,my_condition为True
[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  vars:
    my_condition: True
  tasks:
    - name: 安装阿帕奇
      yum:
        name: httpd
        state: present
      when: my_condition

4.查看受控机是否安装阿帕奇(已安装)

[root@localhost ~]# rpm -qa|grep httpd
httpd-filesystem-2.4.37-21.module_el8.2.0+382+15b0afa8.noarch
centos-logos-httpd-80.5-2.el8.noarch
httpd-2.4.37-21.module_el8.2.0+382+15b0afa8.x86_64
httpd-tools-2.4.37-21.module_el8.2.0+382+15b0afa8.x86_64
  • 示例: my_service变量未被定义时,则不会安装
    1 . 变量未被定义
[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  tasks:
    - name: 安装阿帕奇
      yum:
        name: "{{ my_service }}"
        state: present
      when: my_service is defined       
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [安装阿帕奇] *******************************************************************         变量未被定义,则无法识别安装什么东西,所以直接跳过安装
skipping: [192.168.50.136]

PLAY RECAP *********************************************************************
192.168.50.136             : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
  1. 定义空变量
[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  vars:
    my_service: “ ”                                   这里定义空变量
  tasks:
    - name: 安装阿帕奇
      yum:
        name: "{{ my_service }}"
        state: present
      when: my_service is defined
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [安装阿帕奇] *******************************************************************   无法识别安装什么东西,直接跳过安装
skipping: [192.168.50.136]

PLAY RECAP *********************************************************************
192.168.50.136             : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
  1. 给变量定义httpd
[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  vars:
    my_service: httpd                                             给变量定义httpd
  tasks:
    - name: 安装阿帕奇
      yum:
        name: "{{ my_service }}"
        state: present
      when: my_service is defined      
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [安装阿帕奇] *******************************************************************
changed: [192.168.50.136]

PLAY RECAP *********************************************************************
192.168.50.136             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

查看受控机是否安装
[root@localhost ~]# rpm -qa|grep httpd
httpd-tools-2.4.37-21.module_el8.2.0+382+15b0afa8.x86_64
httpd-filesystem-2.4.37-21.module_el8.2.0+382+15b0afa8.noarch
centos-logos-httpd-80.5-2.el8.noarch
httpd-2.4.37-21.module_el8.2.0+382+15b0afa8.x86_64

示例条件

操作示例
等于(值为字符串)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的求值为Truememory_available
布尔变量是False。0、False或no的求值为Falsenot memory_available
第一个变量的值存在,作为第二个变量的列表中的值ansible_distribution in supported_distros
  • when语句不是模块变量,它必须通过缩进到任务的最高级别,放置在模块的外面。
  • when关键字放在任务名称和模块(及模块参数)的后面。

2.2 测试多个条件

一个when语句可用于评估多个条件。使用and和or关键字组合条件,并使用括号分组条件。

示例: 使用and运算,两个条件都必须为真,才能满足整个条件语句。

[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  tasks:
    - name: sakdjla
      yum:
        name: httpd
        state: present
      when: ansible_facts['distribution'] == 'RedHat' and ansible_facts['distribution_version'] == '8.2'
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [sakdjla] *****************************************************************
changed: [192.168.50.136]

PLAY RECAP *********************************************************************
192.168.50.136             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


查看受控机是否安装httpd
[root@localhost ~]# rpm -qa|grep httpd
httpd-filesystem-2.4.37-21.module_el8.2.0+382+15b0afa8.noarch
centos-logos-httpd-80.5-2.el8.noarch
httpd-2.4.37-21.module_el8.2.0+382+15b0afa8.x86_64
httpd-tools-2.4.37-21.module_el8.2.0+382+15b0afa8.x86_64

  • 也使用列表来描述条件列表
[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  tasks:
    - name: sakdjla
      yum:
        name: httpd
        state: present
      when:
        - ansible_facts['distribution'] == 'RedHat'
        - ansible_facts['distribution_version'] == '8.2'
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [sakdjla] *****************************************************************
changed: [192.168.50.136]

PLAY RECAP *********************************************************************
192.168.50.136             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
  • 使用or语句时,满足其中一个条件就可执行
[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  tasks:
    - name: sakdjla
      yum:
        name: httpd
        state: present
      when: >        
        ansible_facts['distribution'] == 'RedHat'                    该条件成立
        or         
        ansible_facts['distribution_version'] == '8.1'               我把'8.2' 改成‘8.1’ ,所以该条件不成立
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [sakdjla] *****************************************************************
changed: [192.168.50.136]

PLAY RECAP *********************************************************************
192.168.50.136             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


查看受控机是否安装(已安装)
[root@localhost ~]# rpm -qa|grep httpd
httpd-tools-2.4.37-21.module_el8.2.0+382+15b0afa8.x86_64
httpd-filesystem-2.4.37-21.module_el8.2.0+382+15b0afa8.noarch
centos-logos-httpd-80.5-2.el8.noarch
httpd-2.4.37-21.module_el8.2.0+382+15b0afa8.x86_64

2.3 组合循环和有条件任务

示例: 需要卸载受控机的阿帕奇,当>那个值时,则会卸载;反之,不会执行

[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  tasks:
    - name: alkdjlak
      yum:
        name: httpd
        state: absent                                                   卸载受控机阿帕奇
      loop: "{{ ansible_facts['mounts'] }}"
      when:
        - item.mount == '/'
        - item.size_available > 913895410                    这里是大于数值,则会执行任务
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [alkdjlak] ****************************************************************
changed: [192.168.50.136] => (item={'mount': '/', 'device': '/dev/mapper/rhel-root', 'fstype': 'xfs', 'options': 'rw,seclabel,relatime,attr2,inode64,noquota', 'size_total': 18238930944, 'size_available': 16655716352, 'block_size': 4096, 'block_total': 4452864, 'block_available': 4066337, 'block_used': 386527, 'inode_total': 8910848, 'inode_available': 8876067, 'inode_used': 34781, 'uuid': '0579379e-7e27-495a-bb7b-a19916aa0929'})
skipping: [192.168.50.136] => (item={'mount': '/boot', 'device': '/dev/nvme0n1p1', 'fstype': 'xfs', 'options': 'rw,seclabel,relatime,attr2,inode64,noquota', 'size_total': 1063256064, 'size_available': 895655936, 'block_size': 4096, 'block_total': 259584, 'block_available': 218666, 'block_used': 40918, 'inode_total': 524288, 'inode_available': 523988, 'inode_used': 300, 'uuid': '81d21a3c-30eb-45e4-b99f-6536b0688395'}) 

PLAY RECAP *********************************************************************
192.168.50.136             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


查看受控机阿帕奇是否卸载
[root@localhost ~]# rpm -qa|grep httpd
httpd-tools-2.4.37-21.module_el8.2.0+382+15b0afa8.x86_64
httpd-filesystem-2.4.37-21.module_el8.2.0+382+15b0afa8.noarch
centos-logos-httpd-80.5-2.el8.noarch
  • 现在需要安装阿帕奇。用<数值,则条件语句不成立,任务不会执行
[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  tasks:
    - name: alkdjlak
      yum:
        name: httpd
        state: present                                           安装阿帕奇
      loop: "{{ ansible_facts['mounts'] }}"
      when:
        - item.mount == '/'
        - item.size_available < 913895410                        小于数值,条件语句不成立,任务不执行
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [alkdjlak] ****************************************************************
skipping: [192.168.50.136] => (item={'mount': '/', 'device': '/dev/mapper/rhel-root', 'fstype': 'xfs', 'options': 'rw,seclabel,relatime,attr2,inode64,noquota', 'size_total': 18238930944, 'size_available': 16662544384, 'block_size': 4096, 'block_total': 4452864, 'block_available': 4068004, 'block_used': 384860, 'inode_total': 8910848, 'inode_available': 8876651, 'inode_used': 34197, 'uuid': '0579379e-7e27-495a-bb7b-a19916aa0929'}) 
skipping: [192.168.50.136] => (item={'mount': '/boot', 'device': '/dev/nvme0n1p1', 'fstype': 'xfs', 'options': 'rw,seclabel,relatime,attr2,inode64,noquota', 'size_total': 1063256064, 'size_available': 895655936, 'block_size': 4096, 'block_total': 259584, 'block_available': 218666, 'block_used': 40918, 'inode_total': 524288, 'inode_available': 523988, 'inode_used': 300, 'uuid': '81d21a3c-30eb-45e4-b99f-6536b0688395'}) 

PLAY RECAP *********************************************************************
192.168.50.136             : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   


查看受控机并没有安装阿帕奇
[root@localhost ~]# rpm -qa|grep httpd
httpd-tools-2.4.37-21.module_el8.2.0+382+15b0afa8.x86_64
httpd-filesystem-2.4.37-21.module_el8.2.0+382+15b0afa8.noarch
centos-logos-httpd-80.5-2.el8.noarch

3. 实施处理程序

3.1 handlers

示例: 只有配置文件更新并且通知了该任务,restart apache处理程序才会重启Apache服务器

1.在受控机上把httpd.conf转移到主控机的root1下面去

[root@localhost ~]# cd /etc/httpd
[root@localhost httpd]# ls
conf    conf.modules.d  modules  state
conf.d  logs            run
[root@localhost httpd]# cd conf
[root@localhost conf]# ls
httpd.conf  httpd.conf.rpmsave  magic
[root@localhost conf]# scp httpd.conf 192.168.50.135:/root/
root@192.168.50.135's password: 
httpd.conf          100%   12KB  11.2MB/s   00:00    


主控机上查看
[root@localhost playbook]# ls ~
anaconda-ks.cfg  hosts       playbook
ansible.cfg      httpd.conf
  1. 创建一个files,与myplay.yml平级
[root@localhost playbook]# ls
!  myplay.yml
[root@localhost playbook]# mkdir files
[root@localhost playbook]# ls
!  files  myplay.yml
[root@localhost playbook]# mv ~/httpd.conf files/             把root下面的httpd.conf移到files
[root@localhost playbook]# tree .
.
├── !
├── files
│   └── httpd.conf
└── myplay.yml

1 directory, 3 files
  1. 编写playbook并运行
[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  tasks:
    - name: installed httpd
      yum:
        name: httpd
        state: present

    - name: provides config
      template:
        src: files/httpd.conf
        dest: /etc/httpd/conf/httpd.conf
      notify:
        - restart apache

    - name: start service
      service:
        name: httpd
        state: started

  handlers:
    - name: restart apache
      service:
        name: httpd
        state: restarted
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [installed httpd] *********************************************************
ok: [192.168.50.136]

TASK [provides config] *********************************************************           因为主控机和被控机的配置文件不一样(主控机的注释被取消),所以每次执行此步骤都会执行一遍
changed: [192.168.50.136]

TASK [start service] ***********************************************************
ok: [192.168.50.136]

RUNNING HANDLER [restart apache] ***********************************************
changed: [192.168.50.136]

PLAY RECAP *********************************************************************
192.168.50.136             : ok=5    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
  1. 在主控机进入files将ServerName的注释取消,但被控机的注释存在,所以两台主机的配置文件不一样
[root@localhost playbook]# ls
!  files  myplay.yml
[root@localhost playbook]# cd files
[root@localhost files]# ls
httpd.conf
[root@localhost files]# vim httpd.conf 
......
#ServerName www.example.com:80                      将主控机的注释取消,被控机的注释依然存在
......

5.查看被控机的服务

[root@localhost ~]# systemctl status httpd
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; >
   Active: active (running) since Mon 2020-09-07 16:31:37 >

[root@localhost ~]# systemctl status httpd
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; >
   Active: active (running) since Mon 2020-09-07 16:42:53 >          因为两台主机的配置文件不一样,所以被控机的服务每次都会执行一次,所以时间会更新

3.2 使用处理程序的好处

使用处理程序时需要牢记几个重要事项:

  • 处理程序始终按照play的handlers部分指定的顺序运行。它们不按在任务中由notify语句列出的顺序运行,或按任务通知它们的顺序运行。

  • 处理程序通常在相关play中的所有其他任务完成后运行。playbook的tasks部分中某一任务调用的处理程序,将等到tasks下的所有任务都已处理后才会运行。

  • 处理程序名称存在于各play命名空间中。如果两个处理程序被错误地给予相同的名称,则仅会运行一个。

  • 即使有多个任务通知处理程序,该处理程序依然仅运行一次。如果没有任务通知处理程序,它就不会运行。

  • 如果包含notify语句的任务没有报告changed结果(例如,软件包已安装并且任务报告ok),则处理程序不会获得通知。处理程序将被跳过,直到有其他任务通知它。只有相关任务报告了changed状态,Ansible才会通知处理程序。

4. 处理任务失败

4.1 忽略任务失败

  • ignore_errors可以让playbook在任务失败时继续执行
[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  tasks:
    - name: SAKDJALKAJ
      yum:
        name: ndasdks                        安装一个不存在的东西,所以该命令必定失败
        state: present
      ignore_errors: yes                     可以忽略失败的任务使其他任务继续执行


    - name: lakjdkasj                        该任务必定成功
      command: echo "hello world"
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [SAKDJALKAJ] **************************************************************                      该任务失败并没有影响其他任务的执行
fatal: [192.168.50.136]: FAILED! => {"changed": false, "failures": ["No package ndasdks available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}
...ignoring

TASK [lakjdkasj] ***************************************************************
changed: [192.168.50.136]

PLAY RECAP *********************************************************************
192.168.50.136             : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=1   

4.2 任务失败后强制执行

  • 成功案例
[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  tasks:
    - name: install
      yum:
        name: httpd
        state: present


    - name: config
      template:
        src: files/httpd1.conf
        dest: /etc/httpd/conf/httpd.conf
      notify:                                  该任务若是失败,则会通知handlers任务不执行
        - restart apache


    - name: service
      service:
        name: httpd
        state: started


  handlers:
    - name: restart apache
      service:
        name: httpd
        state: restarted
[root@localhost playbook]# ansible-playbook --syntax-check myplay.yml 

playbook: myplay.yml
[root@localhost playbook]# ls
!  files  myplay.yml
[root@localhost playbook]# ls files/
httpd.conf
[root@localhost playbook]# echo '#' >> files/httpd.conf                         改变配置文件,则会重新运行配置文件任务
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [install] *****************************************************************
ok: [192.168.50.136]

TASK [config] ******************************************************************
changed: [192.168.50.136]

TASK [service] *****************************************************************
ok: [192.168.50.136]

RUNNING HANDLER [restart apache] ***********************************************
changed: [192.168.50.136]

PLAY RECAP *********************************************************************
192.168.50.136             : ok=5    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
  • 失败案例
[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  tasks:
    - name: install
      yum:
        name: httpd
        state: present


    - name: config
      template:
        src: files/httpd1.conf                     httpd1.conf不存在,所以该任务会运行失败
        dest: /etc/httpd/conf/httpd.conf
      notify:                                      该任务失败后,后面的任务也不会执行
        - restart apache


    - name: service
      service:
        name: httpd
        state: started


  handlers:
    - name: restart apache
      service:
        name: httpd
        state: restarted
[root@localhost playbook]# echo '#' >> files/httpd.conf
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [install] *****************************************************************
ok: [192.168.50.136]

TASK [config] ******************************************************************
fatal: [192.168.50.136]: FAILED! => {"changed": false, "msg": "Could not find or access 'files/httpd1.conf'\nSearched in:\n\t/root/playbook/templates/files/httpd1.conf\n\t/root/playbook/files/httpd1.conf\n\t/root/playbook/templates/files/httpd1.conf\n\t/root/playbook/files/httpd1.conf on the Ansible Controller.\nIf you are using a module and expect the file to exist on the remote, see the remote_src option"}

PLAY RECAP *********************************************************************
192.168.50.136             : ok=2    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
  1. force_handlers: yes,配置文件发生改变才会执行;没有改变则不会执行
第一遍配置文件发生改变,所以执行了

[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [install] *****************************************************************
ok: [192.168.50.136]

TASK [config] ******************************************************************
changed: [192.168.50.136]

TASK [service] *****************************************************************
ok: [192.168.50.136]

RUNNING HANDLER [restart apache] ***********************************************
changed: [192.168.50.136]

PLAY RECAP *********************************************************************
192.168.50.136             : ok=5    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   



第二遍配置文件没有改变则没有执行

[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [install] *****************************************************************
ok: [192.168.50.136]

TASK [config] ******************************************************************
ok: [192.168.50.136]

TASK [service] *****************************************************************
ok: [192.168.50.136]

PLAY RECAP *********************************************************************
192.168.50.136             : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

示例: 验证重启服务失败不会影响handlers任务的执行

[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  force_handlers: yes
  tasks:
    - name: install
      yum:
        name: httpd
        state: present


    - name: config
      template:
        src: files/httpd.conf
        dest: /etc/httpd/conf/httpd.conf
      notify:
        - restart apache


    - name: service
      service:
        name: httpd
        state: reloade                  该任务必定不会执行,正确执行时应是reloaded


  handlers:
    - name: restart apache
      service:
        name: httpd
        state: restarted

[root@localhost playbook]# echo '#' >> files/httpd.conf                        改变配置文件
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [install] *****************************************************************
ok: [192.168.50.136]

TASK [config] ******************************************************************
changed: [192.168.50.136]

TASK [service] *****************************************************************               重启服务任务没有执行
fatal: [192.168.50.136]: FAILED! => {"changed": false, "msg": "value of state must be one of: reloaded, restarted, started, stopped, got: reloade"}

RUNNING HANDLER [restart apache] ***********************************************                 hanglers任务已执行
changed: [192.168.50.136]

PLAY RECAP *********************************************************************
192.168.50.136             : ok=4    changed=2    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

4.3 指定任务失败条件

使用failed_when关键字来指定表示任务已失败的条件

示例:

编写一个脚本
[root@localhost playbook]# cd files/
[root@localhost files]# ls
httpd.conf
[root@localhost files]# vim test.sh

#!/bin/bash

ls jdkhaskda                              不存在
ls                                        存在

[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  tasks:
    - name: command
      script: files/test.sh
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [command] *****************************************************************          这里看着成功运行了,其实并没有。脚本在这里看不出来是否运行成功
changed: [192.168.50.136]

PLAY RECAP *********************************************************************
192.168.50.136             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   





查找报错信息
[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  gather_facts: no
  tasks:
    - name: command
      script: files/test.sh
      register: result
      failed_when: "'No such file or directory' in result.stdout"

[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [command] *****************************************************************                 显示报错信息
fatal: [192.168.50.136]: FAILED! => {"changed": true, "failed_when_result": true, "rc": 0, "stderr": "Shared connection to 192.168.50.136 closed.\r\n", "stderr_lines": ["Shared connection to 192.168.50.136 closed."], "stdout": "ls: cannot access 'jdkhaskda': No such file or directory\r\nanaconda-ks.cfg\r\n", "stdout_lines": ["ls: cannot access 'jdkhaskda': No such file or directory", "anaconda-ks.cfg"]}

PLAY RECAP *********************************************************************
192.168.50.136             : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   



用一句话报错
[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  gather_facts: no
  tasks:
    - name: command
      script: files/test.sh
      register: result
      ignore_errors: yes


    - name: error
      fail:                              fail模块也可用于强制任务失败
        msg: "哈哈哈,有错误"
      failed_when: "'No such file or directory' in result.stdout"
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [command] *****************************************************************
changed: [192.168.50.136]

TASK [error] *******************************************************************
fatal: [192.168.50.136]: FAILED! => {"changed": false, "failed_when_result": true, "msg": "哈哈哈,有错误"}

PLAY RECAP *********************************************************************
192.168.50.136             : ok=1    changed=1    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

4.4 指定任务报告何时出现“Changed” 结果

  • changed_when: false 不管配置文件是否发生改变,运行结果都会显示ok(没改变)
先把hehe写入files文件里
[root@localhost playbook]# ls
!  files  myplay.yml
[root@localhost playbook]# cd files
[root@localhost files]# echo 'hehe' > abc
[root@localhost files]# ls
abc  httpd.conf


这里我修改了配置文件,使用changed_when: false , 其结果依然显示ok(没改变)
[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  tasks:
    - name: ksahk
      template:
        src: files/abc
        dest: /tmp/abc
      changed_when: false
[root@localhost playbook]# echo '#' >> files/abc                    修改了配置文件
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [ksahk] *******************************************************************             运行结果显示OK
ok: [192.168.50.136]

PLAY RECAP *********************************************************************
192.168.50.136             : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
  • changed_when: True 不管配置文件是否发生改变,其结果都会显示changed(发生改变)
这里我没有修改配置文件,使用changded_when: True,其结果会显示为changed

[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  tasks:
    - name: ksahk
      template:
        src: files/abc
        dest: /tmp/abc
      changed_when: True
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [ksahk] *******************************************************************
changed: [192.168.50.136]

PLAY RECAP *********************************************************************
192.168.50.136             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

4.5 Ansible块和错误处理

  • block:定义要运行的主要任务
  • rescue:定义要在block子句中定义的任务失败时运行的任务
  • always:定义始终都独立运行的任务,不论block和rescue子句中定义的任务是成功还是失败

示例: block执行失败,则rescue执行;block成功执行,则rescue不会执行;always始终执行

block执行失败,则rescue执行
[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  tasks:
    - name: test
      block:
      - name: block
        command: echo "block"                   执行必定成功
      - name: failed task                       该任务必定执行失败,所以rescue会执行
        command: ls sajkdha
      rescue:
      - name: rescure
        command: echo "rescue"
      always:
      - name: always
        command: echo "always"
[root@localhost playbook]# ansible-playbook --syntax-check myplay.yml 

playbook: myplay.yml
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [block] *******************************************************************
changed: [192.168.50.136]

TASK [failed task] *************************************************************             执行失败
fatal: [192.168.50.136]: FAILED! => {"changed": true, "cmd": ["ls", "sajkdha"], "delta": "0:00:00.004438", "end": "2020-09-08 09:57:06.391297", "msg": "non-zero return code", "rc": 2, "start": "2020-09-08 09:57:06.386859", "stderr": "ls: cannot access 'sajkdha': No such file or directory", "stderr_lines": ["ls: cannot access 'sajkdha': No such file or directory"], "stdout": "", "stdout_lines": []}

TASK [rescure] *****************************************************************          执行
changed: [192.168.50.136]

TASK [always] ******************************************************************
changed: [192.168.50.136]

PLAY RECAP *********************************************************************
192.168.50.136             : ok=4    changed=3    unreachable=0    failed=0    skipped=0    rescued=1    ignored=0   





block执行成功,则rescue不会执行
[root@localhost playbook]# vim myplay.yml 

---
- hosts: all
  tasks:
    - name: test
      block:
      - name: block
        command: echo "block"           执行必定成功
      - name: failed task
        command: ls                     执行必定成功
      rescue:
      - name: rescure                   所以rescue不会执行
        command: echo "rescue"
      always:
      - name: always
        command: echo "always"
[root@localhost playbook]# ansible-playbook myplay.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.50.136]

TASK [block] *******************************************************************
changed: [192.168.50.136]

TASK [failed task] *************************************************************
changed: [192.168.50.136]

TASK [always] ******************************************************************
changed: [192.168.50.136]

PLAY RECAP *********************************************************************
192.168.50.136             : ok=4    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

百慕卿君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值