0
点赞
收藏
分享

微信扫一扫

ansible学习笔记05

实现任务控制,可以处理一些预料之中的错误,让程序更加高效执行,完成更复杂的项目

1、loops循环

使用循环可以灵活的管理很多数据

1.1 通过变量文件写loop循环

[student@workstation ansible-var]$ cat group_vars/all
# 定义变量矩阵,存储相关信息
---
packages:
  - name: httpd
    state: started

  - name: firewalld
    state: started

[student@workstation ansible-var]$ cat install.yml
# 使用循环安装软件包和服务
---
- name: define var in playbook
  hosts: all
# 由于是通过group_vars目录下指定的all文件,所以此步骤可以忽略
# vars_files:
#       - group_vars/all
  tasks:
          - name: install server
            yum:
                    name: "{{ item['name'] }}"
                    state: latest
            loop: "{{ packages }}"
          - name: start service
            service:
                    name: "{{ item['name'] }}"
                    state: "{{ item.state }}"
                    enabled: yes
            loop: "{{ packages }}"
[student@workstation ansible-var]$ ansible-playbook install.yml

PLAY [define var in playbook] ***************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************************************************************************************************************************************************
ok: [serverd]
ok: [servera]
ok: [serverc]
ok: [serverb]

TASK [install server] ***********************************************************************************************************************************************************************************************************************************
ok: [serverb] => (item={'name': 'httpd', 'state': 'started'})
ok: [serverc] => (item={'name': 'httpd', 'state': 'started'})
ok: [serverd] => (item={'name': 'httpd', 'state': 'started'})
ok: [servera] => (item={'name': 'httpd', 'state': 'started'})
ok: [serverb] => (item={'name': 'firewalld', 'state': 'started'})
ok: [serverd] => (item={'name': 'firewalld', 'state': 'started'})
ok: [serverc] => (item={'name': 'firewalld', 'state': 'started'})
ok: [servera] => (item={'name': 'firewalld', 'state': 'started'})

TASK [start service] ************************************************************************************************************************************************************************************************************************************
changed: [servera] => (item={'name': 'httpd', 'state': 'started'})
changed: [serverb] => (item={'name': 'httpd', 'state': 'started'})
changed: [serverc] => (item={'name': 'httpd', 'state': 'started'})
changed: [serverd] => (item={'name': 'httpd', 'state': 'started'})
ok: [servera] => (item={'name': 'firewalld', 'state': 'started'})
ok: [serverb] => (item={'name': 'firewalld', 'state': 'started'})
changed: [serverc] => (item={'name': 'firewalld', 'state': 'started'})
changed: [serverd] => (item={'name': 'firewalld', 'state': 'started'})

PLAY RECAP **********************************************************************************************************************************************************************************************************************************************
servera                    : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverb                    : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverc                    : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverd                    : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

1.2 直接在playbook定义变量循环

# 使用循环安装软件包和服务,直接定义在playbook中,生产环境下不建议使用
---
- name: define var in playbook
  hosts: all
  vars:
          packages:
                  - name: httpd
                    state: started

                  - name: firewalld
                    state: started
  tasks:
          - name: install server
            yum:
                    name: "{{ item['name'] }}"
                    state: latest
            loop: "{{ packages }}"
          - name: start service
            service:
                    name: "{{ item['name'] }}"
                    state: "{{ item.state }}"
                    enabled: yes
            loop: "{{ packages }}"

1.3 with循环

在ansible2.5之前,使用的是with循环,该方法已经被淘汰了,with的大部分用法可以被loop替代

loop键 描述
with_items 可以无缝替换成loop,遍历一串字符
with_file 列出控制节点文件名,使用文件列表的相应内容
with_sequence 在每次迭代期间以生成的顺序生成项
[student@workstation ansible-var]$ cat items.yml
---
- name: "were prefixed with:with_"
  hosts: all
  gather_facts: no
  vars:
          home:
                  - xiaoming
                  - xiaohong
                  - xiaoming
                  - mmx
  tasks:
          - name: use with
            debug:
                  msg: "An item: {{ item }}"
            with_items: "{{ home }}"
[student@workstation ansible-var]$ ansible-playbook items.yml -C

PLAY [were prefixed with:with_] *************************************************************************************************************************************************************************************************************************

TASK [use with] *****************************************************************************************************************************************************************************************************************************************
ok: [servera] => (item=xiaoming) => {
    "msg": "An item: xiaoming"
}
ok: [servera] => (item=xiaohong) => {
    "msg": "An item: xiaohong"
}
ok: [servera] => (item=xiaoming) => {
    "msg": "An item: xiaoming"
}
ok: [servera] => (item=mmx) => {
    "msg": "An item: mmx"
}
ok: [serverc] => (item=xiaoming) => {
    "msg": "An item: xiaoming"
}
ok: [serverc] => (item=xiaohong) => {
    "msg": "An item: xiaohong"
}
ok: [serverc] => (item=xiaoming) => {
    "msg": "An item: xiaoming"
}
ok: [serverc] => (item=mmx) => {
    "msg": "An item: mmx"
}
ok: [serverb] => (item=xiaoming) => {
    "msg": "An item: xiaoming"
}
ok: [serverd] => (item=xiaoming) => {
    "msg": "An item: xiaoming"
}
ok: [serverd] => (item=xiaohong) => {
    "msg": "An item: xiaohong"
}
ok: [serverd] => (item=xiaoming) => {
    "msg": "An item: xiaoming"
}
ok: [serverd] => (item=mmx) => {
    "msg": "An item: mmx"
}
ok: [serverb] => (item=xiaohong) => {
    "msg": "An item: xiaohong"
}
ok: [serverb] => (item=xiaoming) => {
    "msg": "An item: xiaoming"
}
ok: [serverb] => (item=mmx) => {
    "msg": "An item: mmx"
}

1.4 使用egister字段捕获task任务

[root@mmx_ansible ansible_taskcontol]# cat vars/hello.yml
---
hostname: localhost

family:
        - name: xiaoming
          age: 18
          like: draw
        - name: xiaogang
          age: 22
          like: sing
        - name: mmx
          age: 22
          like: play games
[root@mmx_ansible ansible_taskcontol]# cat with_list.yml
---
- name: user loop
  hosts: "{{ hostname }}"
  vars_files:
          - vars/hello.yml
  tasks:
          - name: one
            debug:
                    msg: hello world
          - name: two
            debug:
                    msg: "family members have {{ item['name'] }}"
            # loop: "{{ family }}"
            with_list: "{{ family }}"
            register: echo_results
          - debug: var=echo_results

在"results": [……]字段中可以找到一些有用的信息

  1. item遍历的一些参数
  2. msg输出的一些结果
TASK [debug] *******************************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "echo_results": {
        "changed": false,
        "msg": "All items completed",
        "results": [
            {
                "ansible_loop_var": "item",
                "changed": false,
                "failed": false,
                # 这里列出了变量矩阵中的一些参数
                "item": {
                    "age": 18,
                    "like": "draw",
                    "name": "xiaoming"
                },
                # 这里可以看到msg参数的输出结果
                "msg": "family members have xiaoming"
            },
            {
                "ansible_loop_var": "item",
                "changed": false,
                "failed": false,
                "item": {
                    "age": 22,
                    "like": "sing",
                    "name": "xiaogang"
                },
                "msg": "family members have xiaogang"
            },
            {
                "ansible_loop_var": "item",
                "changed": false,
                "failed": false,
                "item": {
                    "age": 22,
                    "like": "play games",
                    "name": "mmx"
                },
                "msg": "family members have mmx"
            }
        ],
        "skipped": false
    }
}

2、 task中的条件判断

通过判断系统的相关信息(比如可用内存),或者command中输出的命令,facts变量等参数,都能让计算机在通过条件判断的方式,做出对应策略

2.1 条件判断语法

使用when关键字指定需要判断的task

2.2 通过变量开关作为判断条件

状态
True 正确(开)
yes 正确(开)
1 正确(开)
False 错误(关)
no 错误(关)
0 错误(关)
[root@mmx_ansible ansible_taskcontol]# cat conditional_syntax.yml
---
- name: 条件判断
  hosts: all
  vars:
          # 通过这个开关来确定when是否执行
          whether_run: yes
  tasks:
          - name: 输出hello
            debug:
                    msg: hello!
            register: mmx
            when: whether_run
          - debug: var=mmx
[root@mmx_ansible ansible_taskcontol]# ansible-playbook conditional_syntax.yml

PLAY [条件判断] ****************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************************************************************************************************************
[WARNING]: Platform linux on host localhost is using the discovered Python interpreter at /usr/bin/python3.8, but future installation of another Python interpreter could change the meaning of that path. See
https://docs.ansible.com/ansible-core/2.12/reference_appendices/interpreter_discovery.html for more information.
ok: [localhost]

TASK [输出hello] ***************************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": "hello!"
}

TASK [debug] *******************************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "mmx": {
        "changed": false,
        "failed": false,
        "msg": "hello!"
    }
}

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

2.3 通过defind或undefined作为判断条件

# 定义的变量文件
[root@mmx_ansible ansible_taskcontol]# cat vars/package.yml
---
packages:
        - name: httpd
          state: latest
        - name: firewalld
          state: present

[root@mmx_ansible ansible_taskcontol]# cat exist_not.yml
---
- name: 判断是否存在
  hosts: all
  vars_files:
          - vars/package.yml
  tasks:
          - name: 判断字段是否存在1
            debug:
                    msg: "名称 {{ item.name }}"
            loop: "{{ packages }}"
            when: item.name is defined
          - name: 判断字段是否存在2
            debug:
                    msg: "状态 {{ item.state }}"
            loop: "{{ packages }}"
            when: item.state is defined
          - name: 判断字段是否存在3
            debug:
                    msg: "版本 {{ item.version }}"
            loop: "{{ packages }}"
            when: item.version is defined
# 由于最后一个version在变量文件中不存在,所有不会执行
[root@mmx_ansible ansible_taskcontol]# ansible-playbook exist_not.yml

PLAY [判断是否存在] ************************************************************************************************************************************************************************************************************

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

TASK [判断字段是否存在1] *******************************************************************************************************************************************************************************************************
ok: [localhost] => (item={'name': 'httpd', 'state': 'latest'}) => {
    "msg": "名称 httpd"
}
ok: [localhost] => (item={'name': 'firewalld', 'state': 'present'}) => {
    "msg": "名称 firewalld"
}

TASK [判断字段是否存在2] *******************************************************************************************************************************************************************************************************
ok: [localhost] => (item={'name': 'httpd', 'state': 'latest'}) => {
    "msg": "状态 latest"
}
ok: [localhost] => (item={'name': 'firewalld', 'state': 'present'}) => {
    "msg": "状态 present"
}

2.4 常用的判断条件

操作 示例
是否等于(字符串) ansible_machine == 'x86_64'
是否等于(数字) max_memory == 512
小于 min_memory < 128
大于 min_memory > 128
小于等于 min_memory <= 128
大于等于 min_memory >= 128
不等于 min_memory != 128
已定义 min_memory is defined
未定义 min_memory is undefined
是否为真(1、True、yes) memory_available
是否为假(0、False、no) not memory_available
在其中包含 ansible_distribution in supported_distors

2.5 使用in参数

---
- name: 系统版本
  hosts: all
  vars:
          supported_distros:
                  - RedHat
                  - Fedora
                  - Rocky
  tasks:
          - name: one
            debug:
                    msg: "{{ ansible_distribution }}"
            # 判断系统架构是否在支持列表里面
            when: ansible_distribution in supported_distros
[root@mmx_ansible ansible_taskcontol]# ansible-playbook ainb.yml

PLAY [系统版本] ****************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************************************************************************************************************
[WARNING]: Platform linux on host localhost is using the discovered Python interpreter at /usr/bin/python3.8, but future installation of another Python interpreter could change the meaning of that path. See
https://docs.ansible.com/ansible-core/2.12/reference_appendices/interpreter_discovery.html for more information.
ok: [localhost]

TASK [one] *********************************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": "Rocky"
}

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

2.6 多条件判断

# 判断系统和版本
[root@mmx_ansible ansible_taskcontol]# cat multiple.yaml
---
- name: 系统版本
  hosts: all
  vars:
          supported_distros:
                  - RedHat
                  - Fedora
                  - Rocky
          version:
                  - "8.0"
                  - "8.2"
                  - "8.5"
                  - "7.0"
  tasks:
          - name: one
            debug:
                    msg: "distribution:{{ ansible_distribution }} version: {{ ansible_distribution_version }} "
            when: ansible_distribution in supported_distros and ansible_distribution_version in version
[root@mmx_ansible ansible_taskcontol]# ansible-playbook multiple.yaml

PLAY [系统版本] ****************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************************************************************************************************************
[WARNING]: Platform linux on host localhost is using the discovered Python interpreter at /usr/bin/python3.8, but future installation of another Python interpreter could change the meaning of that path. See
https://docs.ansible.com/ansible-core/2.12/reference_appendices/interpreter_discovery.html for more information.
ok: [localhost]

TASK [one] *********************************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": "distribution:Rocky version: 8.5 "
}

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

2.7 loop和条件判断混合使用

[student@workstation ansible-var]$ cat loop_conditional.yml
---
- name: loop和when混合使用
  hosts: all
  tasks:
          - name: install package
            debug:
                    msg: hello world
            loop: "{{ ansible_mounts }}"
            # 判断item.mount和item.size_available是否符合要求
            when: item.mount == '/' and item.size_available > 300000000
[student@workstation ansible-var]$ ansible-playbook loop_conditional.yml

PLAY [loop和when混合使用] ***********************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************************************************************************************************************
ok: [servera]
ok: [serverd]
ok: [serverb]
ok: [serverc]

TASK [install package] *********************************************************************************************************************************************************************************************************
ok: [servera] => (item={'mount': '/', 'device': '/dev/vda1', 'fstype': 'xfs', 'options': 'rw,seclabel,relatime,attr2,inode64,noquota', 'size_total': 10725863424, 'size_available': 9079398400, 'block_size': 4096, 'block_total': 2618619, 'block_available': 2216650, 'block_used': 401969, 'inode_total': 5242304, 'inode_available': 5196022, 'inode_used': 46282, 'uuid': '884f47c9-a69d-4c5b-915d-6b7c9c74c923'}) => {
    "msg": "hello world"
}
ok: [serverb] => (item={'mount': '/', 'device': '/dev/vda1', 'fstype': 'xfs', 'options': 'rw,seclabel,relatime,attr2,inode64,noquota', 'size_total': 10725863424, 'size_available': 8889929728, 'block_size': 4096, 'block_total': 2618619, 'block_available': 2170393, 'block_used': 448226, 'inode_total': 5242304, 'inode_available': 5195789, 'inode_used': 46515, 'uuid': '884f47c9-a69d-4c5b-915d-6b7c9c74c923'}) => {
    "msg": "hello world"
}
ok: [serverc] => (item={'mount': '/', 'device': '/dev/vda1', 'fstype': 'xfs', 'options': 'rw,seclabel,relatime,attr2,inode64,noquota', 'size_total': 10725863424, 'size_available': 9100800000, 'block_size': 4096, 'block_total': 2618619, 'block_available': 2221875, 'block_used': 396744, 'inode_total': 5242304, 'inode_available': 5196134, 'inode_used': 46170, 'uuid': '884f47c9-a69d-4c5b-915d-6b7c9c74c923'}) => {
    "msg": "hello world"
}
ok: [serverd] => (item={'mount': '/', 'device': '/dev/vda1', 'fstype': 'xfs', 'options': 'rw,seclabel,relatime,attr2,inode64,noquota', 'size_total': 10725863424, 'size_available': 9102565376, 'block_size': 4096, 'block_total': 2618619, 'block_available': 2222306, 'block_used': 396313, 'inode_total': 5242304, 'inode_available': 5196136, 'inode_used': 46168, 'uuid': '884f47c9-a69d-4c5b-915d-6b7c9c74c923'}) => {
    "msg": "hello world"
}

PLAY RECAP *********************************************************************************************************************************************************************************************************************
servera                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverb                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverc                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverd                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

2.8 循环和判断练习

2.8.1 题目说明

  1. 启动环境
  2. 在database_dev主机组中安装MaiaDB并且开启服务

    1. 编辑playbook,加入变量mariadb_packages,两个值mariadb-server和python3-PyMySQL
    2. 使用yum模块通过loop的方式安装服务
    3. 使用service模块开启mariadb
    4. 运行playbook
  3. 在database_prod主机组中定义同样的任务,确保系统为RHEL时候才执行
    1. 编辑playbook
    2. 使用ad hoc方式查看系统版本
    3. 执行playbook

2.8.2 练习

[student@workstation ansible-var]$ lab control-flow start

Starting the lab on workstation:

 · Verifying Ansible installation..............................  SUCCESS
 · Creating working directory..................................  SUCCESS
 · Deploying Ansible inventory.................................  SUCCESS
 · Deploying ansible.cfg.......................................  SUCCESS

[student@workstation control-flow]$ cat ansible.cfg
[defaults]
inventory=inventory
remote_user=devops

[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False

[student@workstation control-flow]$ cat inventory
[database_dev]
servera.lab.example.com

[database_prod]
serverb.lab.example.com
# 第二题
[student@workstation control-flow]$ cat playbook.yml
---
- name: 开启MariaDB服务
  hosts: database_dev
  vars:
          mariadb_packages:
                  - mariadb-server
                  - python3-PyMySQL
  tasks:
          - name: one
            yum:
                    name: "{{ item }}"
                    state: present
            loop: "{{ mariadb_packages }}"
          - name: two
            service:
                    name: mariadb
                    state: started
                    enabled: yes
[student@workstation control-flow]$ ansible-playbook playbook.yml

PLAY [开启MariaDB服务] *************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************************************************************************************************************
ok: [servera.lab.example.com]

TASK [one] *********************************************************************************************************************************************************************************************************************
changed: [servera.lab.example.com] => (item=mariadb-server)
ok: [servera.lab.example.com] => (item=python3-PyMySQL)

TASK [two] *********************************************************************************************************************************************************************************************************************
changed: [servera.lab.example.com]

PLAY RECAP *********************************************************************************************************************************************************************************************************************
servera.lab.example.com    : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

[student@workstation control-flow]$
[student@workstation control-flow]$ cat playbook.yml
---
- name: 开启MariaDB服务
  hosts: database_dev
  vars:
          mariadb_packages:
                  - mariadb-server
                  - python3-PyMySQL
  tasks:
          - name: one
            yum:
                    name: "{{ item }}"
                    state: present
            loop: "{{ mariadb_packages }}"
          - name: two
            service:
                    name: mariadb
                    state: started
                    enabled: yes
- name: 运行mariadb
  hosts: database_prod
  vars:
          mariadb_packages:
                  - mariadb-server
                  - python3-PyMySQL
  tasks:
          - name: one
            yum:
                    name: "{{ item }}"
                    state: present
            loop: "{{ mariadb_packages }}"
# 第三题
# 查看系统是不是RHEL
[student@workstation control-flow]$ ansible database_prod -a 'cat /etc/redhat-release' -u devops --become
serverb.lab.example.com | CHANGED | rc=0 >>
Red Hat Enterprise Linux release 8.0 (Ootpa)

[student@workstation control-flow]$ ansible-playbook playbook.yml

PLAY [开启MariaDB服务] *************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************************************************************************************************************
ok: [servera.lab.example.com]

TASK [one] *********************************************************************************************************************************************************************************************************************
ok: [servera.lab.example.com] => (item=mariadb-server)
ok: [servera.lab.example.com] => (item=python3-PyMySQL)

TASK [two] *********************************************************************************************************************************************************************************************************************
ok: [servera.lab.example.com]

PLAY [运行mariadb] ***************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************************************************************************************************************
ok: [serverb.lab.example.com]

TASK [one] *********************************************************************************************************************************************************************************************************************
changed: [serverb.lab.example.com] => (item=mariadb-server)
changed: [serverb.lab.example.com] => (item=python3-PyMySQL)

PLAY RECAP *********************************************************************************************************************************************************************************************************************
servera.lab.example.com    : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
serverb.lab.example.com    : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
# 结束实验
[student@workstation ~]$ lab control-flow finish

Finishing up the lab on servera.lab.example.com:

 · Removing packages on servera
   · Removing mariadb-server...................................  SUCCESS
   · Removing python3-PyMySQL..................................  SUCCESS
 · Removing packages on serverb
   · Removing mariadb-server...................................  SUCCESS
   · Removing python3-PyMySQL..................................  SUCCESS

3、错误控制

一个playbook的执行,有的时候会出现一些预期的错误,playbook检测到错误之后就会停止运行,可以通过错误控制的方式忽略错误,或处理错误,来让playbook顺利执行

3.1 忽略错误

关键字: ignore_errors: yes

[student@workstation control-flow]$ cat mmx.yml
---
- name: ignore_errors关键字
  hosts: database_dev
  vars:
          mariadb_packages:
                  - hello
                  - world
  tasks:
          - name: one
            yum:
                    name: "{{ item }}"
                    state: present
            ignore_errors: yes
            loop: "{{ mariadb_packages }}"
          - debug: msg="hello wold"
# 发现第一个task执行之后,报错了,后面task也能顺利运行
[student@workstation control-flow]$ ansible-playbook mmx.yml

PLAY [ignore_errors关键字] ********************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************************************************************************************************************
ok: [servera.lab.example.com]

TASK [one] *********************************************************************************************************************************************************************************************************************
failed: [servera.lab.example.com] (item=hello) => {"ansible_loop_var": "item", "changed": false, "failures": ["No package hello available."], "item": "hello", "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}
failed: [servera.lab.example.com] (item=world) => {"ansible_loop_var": "item", "changed": false, "failures": ["No package world available."], "item": "world", "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}
...ignoring

TASK [debug] *******************************************************************************************************************************************************************************************************************
ok: [servera.lab.example.com] => {
    "msg": "hello wold"
}

PLAY RECAP *********************************************************************************************************************************************************************************************************************
servera.lab.example.com    : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=1

3.2 强制执行任务失败程序(handlers)

如果允许playbook失败了,可以加上force_handlers:yes这个参数,可以在重新运行playbook的时候一定执行该handlers字段

[student@workstation control-flow]$ cat force_handlers.yml
---
- name: 使用force_handles参数
hosts: all
force_handlers: yes
tasks:
- name: 无论如何都会执行
command: /bin/true
notify: restart the httpd
- name: 安装httpd服务
yum:
name: httpd
state: present
handlers:
- name: restart the httpd
service:
name: httpd
state: restarted

[student@workstation control-flow]$ ansible-playbook force_handlers.yml

PLAY [使用force_handles参数] ***

TASK [Gathering Facts] *****
ok: [servera.lab.example.com]
ok: [serverb.lab.example.com]

TASK [无论如何都会执行] ****
changed: [serverb.lab.example.com]
changed: [servera.lab.example.com]

TASK [安装httpd服务] ***
ok: [servera.lab.example.com]
ok: [serverb.lab.example.com]

RUNNING HANDLER [restart the httpd] ****
changed: [serverb.lab.example.com]
changed: [servera.lab.example.com]

PLAY RECAP *****
servera.lab.example.com : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
serverb.lab.example.com : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0


### 3.3 handlers练习

#### 3.3.1 实验说明

1. 开启实验环境

2. 使用configure_db.yml的playbook文件,安装db_packages,开启db_service服务

3. 下载配置文件config_file_url到目标主机config_file_dst,所有者和所有组为mysql

4. 在yum模块下加入notify: 设置数据库密码,在get_url模块下加入notify:重启数据库,在下方使用handlers通过对应名称执行相应操作

```yaml
  vars:
    db_packages:
      - mariadb-server
      - python3-PyMySQL
    db_service: mariadb
    resources_url: http://materials.example.com/labs/control-handlers
    config_file_url: "{{ resources_url }}/my.cnf.standard"
    config_file_dst: /etc/my.cnf    

3.3.2 练习

[student@workstation ~]$ lab control-handlers start

Starting lab control-handlers on workstation:

 · Verifying Ansible installation..............................  SUCCESS
 · Creating working directory..................................  SUCCESS
 · Deploying Ansible inventory.................................  SUCCESS
 · Deploying ansible.cfg.......................................  SUCCESS
 · Download configure_db.yml...................................  SUCCESS

[student@workstation ~]$ ls
control-errors  control-flow  control-handlers
[student@workstation ~]$ cd control-handlers/
[student@workstation control-handlers]$ ls
ansible.cfg  configure_db.yml  inventory
[student@workstation control-handlers]$ cat ansible.cfg
[defaults]
inventory=inventory
remote_user=devops

[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False
[student@workstation control-handlers]$ cat configure_db.yml
---
- name: Installing MariaDB server
  hosts: databases
  vars:
    db_packages:
      - mariadb-server
      - python3-PyMySQL
    db_service: mariadb
    resources_url: http://materials.example.com/labs/control-handlers
    config_file_url: "{{ resources_url }}/my.cnf.standard"
    config_file_dst: /etc/my.cnf
  tasks:

[student@workstation control-handlers]$ cat inventory
[databases]
servera.lab.example.com
[student@workstation control-handlers]$ cat configure_db.yml
---
- name: Installing MariaDB server
  hosts: databases
  vars:
    db_packages:
      - mariadb-server
      - python3-PyMySQL
    db_service: mariadb
    resources_url: http://materials.example.com/labs/control-handlers
    config_file_url: "{{ resources_url }}/my.cnf.standard"
    config_file_dst: /etc/my.cnf
  tasks:
          - name: install {{ db_packages }}
            yum:
                    name: "{{ db_packages }}"
                    state: present
            notify:
                    - set db password
          - name: start db_service
            service:
                    name: "{{ db_service }}"
                    state: started
                    enabled: 1
          - name: download {{ config_file_url }}
            get_url:
                    url: "{{ config_file_url }}"
                    dest: "{{ config_file_dst }}"
                    owner: mysql
                    group: mysql
                    force: yes
            notify:
                    - restart db service
  handlers:
          - name: restart db_service
            service:
                    name: "{{ db_service }}"
                    state: restart
          - name: set db password
            mysql_user:
                    name: root
                    password: redhat
[student@workstation control-handlers]$ ansible-playbook configure_db.yml 

PLAY [Installing MariaDB server] *****************************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************************************************
ok: [servera.lab.example.com]

TASK [install ['mariadb-server', 'python3-PyMySQL']] *********************************************************************************************
ok: [servera.lab.example.com]

TASK [start db_service] **************************************************************************************************************************
ok: [servera.lab.example.com]

TASK [download http://materials.example.com/labs/control-handlers/my.cnf.standard] ***************************************************************
ok: [servera.lab.example.com]

PLAY RECAP ***************************************************************************************************************************************
servera.lab.example.com    : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

3.4 指定结果“change”

参数: changed_when:false 可以让指定状态。通常在大量shell脚本的时候加入该参数,能发现预期错误

[student@workstation control-flow]$ cat specify_change.yml
---
- name: specify changed
  hosts: all
  tasks:
          - name: "pint (hello world)"
            shell:
                    cmd: echo 123
            register: command_result"
            # 如果输出结果有123,changed就为false
            changed_when: "'123' in command_result['stdout']"
[student@workstation control-flow]$ ansible-playbook specify_change.yml

PLAY [specify changed] *********************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************************************************************************************************************
ok: [servera.lab.example.com]
ok: [serverb.lab.example.com]

TASK [pint (hello world)] ******************************************************************************************************************************************************************************************************
fatal: [servera.lab.example.com]: FAILED! => {"msg": "The conditional check ''123' in command_result['stdout']' failed. The error was: error while evaluating conditional ('123' in command_result['stdout']): Unable to look up a name or access an attribute in template string ({% if '123' in command_result['stdout'] %} True {% else %} False {% endif %}).\nMake sure your variable name does not contain invalid characters like '-': argument of type 'AnsibleUndefined' is not iterable"}
fatal: [serverb.lab.example.com]: FAILED! => {"msg": "The conditional check ''123' in command_result['stdout']' failed. The error was: error while evaluating conditional ('123' in command_result['stdout']): Unable to look up a name or access an attribute in template string ({% if '123' in command_result['stdout'] %} True {% else %} False {% endif %}).\nMake sure your variable name does not contain invalid characters like '-': argument of type 'AnsibleUndefined' is not iterable"}

PLAY RECAP *********************************************************************************************************************************************************************************************************************
servera.lab.example.com    : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0
serverb.lab.example.com    : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

3.5 使用block的方式处理错误

block相当于把task作为一个逻辑组,把一些可能出问题的task放里面

参数 说明
block 作为一个逻辑组
rescue 如果出错了,执行rescue组的任务
always 无论是否出错,都会执行该区域
[student@workstation control-flow]$ !vim
vim block.yml
[student@workstation control-flow]$ cat block.yml
---
- name: 使用block处理错误
  hosts: all
  tasks:
          - name: 使用block作为一个逻辑组
            block:
                    - name: 升级数据库
                      shell:
                              cmd: /usr/local/lib/upgrade-database
            rescue:
                    - name: 回滚数据库
                      shell:
                              cmd: /usr/local/lib/revert-database
            always:
                    - name: 重启数据库
                      service:
                              name: mariadb
                              state: restarted
[student@workstation control-flow]$ ansible-playbook block.yml

PLAY [使用block处理错误] *************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************************************************************************************************************
ok: [serverb.lab.example.com]
ok: [servera.lab.example.com]

TASK [升级数据库] *******************************************************************************************************************************************************************************************************************
fatal: [servera.lab.example.com]: FAILED! => {"changed": true, "cmd": "/usr/local/lib/upgrade-database", "delta": "0:00:00.002169", "end": "2022-07-30 21:12:52.595032", "msg": "non-zero return code", "rc": 127, "start": "2022-07-30 21:12:52.592863", "stderr": "/bin/sh: /usr/local/lib/upgrade-database: No such file or directory", "stderr_lines": ["/bin/sh: /usr/local/lib/upgrade-database: No such file or directory"], "stdout": "", "stdout_lines": []}
fatal: [serverb.lab.example.com]: FAILED! => {"changed": true, "cmd": "/usr/local/lib/upgrade-database", "delta": "0:00:00.002147", "end": "2022-07-30 21:12:52.596637", "msg": "non-zero return code", "rc": 127, "start": "2022-07-30 21:12:52.594490", "stderr": "/bin/sh: /usr/local/lib/upgrade-database: No such file or directory", "stderr_lines": ["/bin/sh: /usr/local/lib/upgrade-database: No such file or directory"], "stdout": "", "stdout_lines": []}

TASK [回滚数据库] *******************************************************************************************************************************************************************************************************************
fatal: [servera.lab.example.com]: FAILED! => {"changed": true, "cmd": "/usr/local/lib/revert-database", "delta": "0:00:00.002238", "end": "2022-07-30 21:12:52.882217", "msg": "non-zero return code", "rc": 127, "start": "2022-07-30 21:12:52.879979", "stderr": "/bin/sh: /usr/local/lib/revert-database: No such file or directory", "stderr_lines": ["/bin/sh: /usr/local/lib/revert-database: No such file or directory"], "stdout": "", "stdout_lines": []}
fatal: [serverb.lab.example.com]: FAILED! => {"changed": true, "cmd": "/usr/local/lib/revert-database", "delta": "0:00:00.002155", "end": "2022-07-30 21:12:52.898294", "msg": "non-zero return code", "rc": 127, "start": "2022-07-30 21:12:52.896139", "stderr": "/bin/sh: /usr/local/lib/revert-database: No such file or directory", "stderr_lines": ["/bin/sh: /usr/local/lib/revert-database: No such file or directory"], "stdout": "", "stdout_lines": []}

TASK [重启数据库] *******************************************************************************************************************************************************************************************************************
fatal: [servera.lab.example.com]: FAILED! => {"changed": false, "msg": "Could not find the requested service mariadb: host"}
changed: [serverb.lab.example.com]

PLAY RECAP *********************************************************************************************************************************************************************************************************************
servera.lab.example.com    : ok=1    changed=0    unreachable=0    failed=2    skipped=0    rescued=1    ignored=0
serverb.lab.example.com    : ok=2    changed=1    unreachable=0    failed=1    skipped=0    rescued=1    ignored=0

3.6 错误控制练习

3.6.1 实验说明

  1. 开启实验环境
  2. 创建一个playbook.yml文件,包含两个tasks
    1. 第一个tasks,有三个变量:web_package:http,db_package:mariadb-server和db_service:mariadb,http的值是错误的
    2. 使用yum模块,安装软件包(变量方式)
    3. 运行playbook,发现错误,加入ignore_errors忽略错误,使用block+rescue方式解决错误
    4. 添加一个always把mariadb服务开启
  3. 第二个tasks查看本地时间
    1. 使用command模块:data查看时间,通过register抓取相关信息
    2. 使用debug模块打印command_result.stdout信息
    3. 使用changed_when:false 标记该任务已完成
    4. 运行playbook
  4. 在第一个安装web_package下使用faild_when: web_package == 'httpd'之后查看运行结果

3.6.2 练习

[student@workstation ~]$ lab control-errors start

Starting lab control-errors on workstation:

 · Verifying Ansible installation..............................  SUCCESS
 · Creating working directory..................................  SUCCESS
 · Deploying Ansible inventory.................................  SUCCESS
 · Deploying ansible.cfg.......................................  SUCCESS
 [student@workstation ~]$ cd control-errors/
[student@workstation control-errors]$ ls
ansible.cfg  inventory
[student@workstation control-errors]$ cat ansible.cfg
[defaults]
inventory=inventory
remote_user=devops

[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False
[student@workstation control-errors]$ cat inventory
[databases]
servera.lab.example.com

使用ignore忽略错误,让play能运行完成

[student@workstation control-errors]$ cat playbook.yml
---
- name: 错误控制练习
  hosts: databases
  vars:
          web_package: http
          db_package: mariadb-server
          db_service: mariadb
  tasks:
          - name: install {{ web_package }}
            yum:
                    name: "{{ web_package }}"
                    state: present
            ignore_errors: yes
          - name: install {{ db_package }}
            yum:
                    name: "{{ db_package }}"
                    state: present
PLAY [错误控制练习] ******************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************************************************************************************************************
ok: [servera.lab.example.com]

TASK [install http] ************************************************************************************************************************************************************************************************************
fatal: [servera.lab.example.com]: FAILED! => {"changed": false, "failures": ["No package http available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}
...ignoring

TASK [install mariadb-server] **************************************************************************************************************************************************************************************************

changed: [servera.lab.example.com]

PLAY RECAP *********************************************************************************************************************************************************************************************************************
servera.lab.example.com    : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=1

使用block+rescue+always处理错误

[student@workstation control-errors]$ cat playbook.yml
---
- name: 错误控制练习
  hosts: databases
  vars:
          web_package: http
          db_package: mariadb-server
          db_service: mariadb
  tasks:
          - name: use block
            block:
                    - name: install {{ web_package }}
                      yum:
                              name: "{{ web_package }}"
                              state: present
                              ignore_errors: yes
            rescue:
                    - name: install {{ web_package }}
                      vars:
                              web_package: httpd
                      yum:
                              name: "{{ web_package }}"
                              state: present
                    - name: install {{ db_package }}
                      yum:
                              name: "{{ db_package }}"
                              state: present
            always:
                    - name: start {{ db_service }}
                      service:
                              name: "{{ db_service }}"
                              state: started
                              enabled: yes
[student@workstation control-errors]$ ansible-playbook playbook.yml

PLAY [错误控制练习] ******************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************************************************************************************************************
ok: [servera.lab.example.com]

TASK [install http] ************************************************************************************************************************************************************************************************************
fatal: [servera.lab.example.com]: FAILED! => {"changed": false, "msg": "Unsupported parameters for (dnf) module: ignore_errors Supported parameters include: allow_downgrade, autoremove, bugfix, conf_file, disable_excludes, disable_gpg_check, disable_plugin, disablerepo, download_dir, download_only, enable_plugin, enablerepo, exclude, install_repoquery, install_weak_deps, installroot, list, lock_timeout, name, releasever, security, skip_broken, state, update_cache, update_only, validate_certs"}

TASK [install httpd] ***********************************************************************************************************************************************************************************************************
ok: [servera.lab.example.com]

TASK [install mariadb-server] **************************************************************************************************************************************************************************************************
ok: [servera.lab.example.com]

TASK [start mariadb] ***********************************************************************************************************************************************************************************************************
ok: [servera.lab.example.com]

PLAY RECAP *********************************************************************************************************************************************************************************************************************
servera.lab.example.com    : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=1    ignored=0
# 最终结果
[student@workstation control-errors]$ cat playbook.yml
---
- name: 错误控制练习
  hosts: databases
  vars:
          web_package: http
          db_package: mariadb-server
          db_service: mariadb
  tasks:
          - name: use block
            block:
                    - name: install {{ web_package }}
                      yum:
                              name: "{{ web_package }}"
                              state: present
                      # 加入该语句,发现变量不为httpd直接跳过
                      failed_when: web_package == 'httpd'
                      ignore_errors: yes
            rescue:
                    - name: install {{ web_package }}
                      vars:
                              web_package: httpd
                      yum:
                              name: "{{ web_package }}"
                              state: present
                    - name: install {{ db_package }}
                      yum:
                              name: "{{ db_package }}"
                              state: present
            always:
                    - name: start {{ db_service }}
                      service:
                              name: "{{ db_service }}"
                              state: started
                              enabled: yes
  tasks:
          - name: 检查时间
            command: date
            register: command_result
            changed_when: false
          - name: print local time
            debug:
                    var: command_result.stdout
[student@workstation control-errors]$ ansible-playbook playbook.yml
 [WARNING]: While constructing a mapping from /home/student/control-errors/playbook.yml, line 2, column 3, found a duplicate dict key (tasks). Using last defined value only.

PLAY [错误控制练习] ******************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************************************************************************************************************
ok: [servera.lab.example.com]

TASK [检查时间] ********************************************************************************************************************************************************************************************************************
ok: [servera.lab.example.com]

TASK [print local time] ********************************************************************************************************************************************************************************************************
ok: [servera.lab.example.com] => {
    "command_result.stdout": "Sat Jul 30 22:04:45 CST 2022"
}

PLAY RECAP *********************************************************************************************************************************************************************************************************************
servera.lab.example.com    : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

# 结束实验
[student@workstation control-errors]$ lab control-errors finish

Finishing lab control-errors on servera.lab.example.com:

 · Removing packages
   · Removing mariadb-server...................................  SUCCESS
   · Removing httpd............................................  SUCCESS

4、 综合实验

举报

相关推荐

0 条评论