Ansible Playbook剧本

Linux / 2020-05-10

Playbook剧本

1、Playbook剧本简介

前面我们都是通过ansible命令形式管理被控节点:
- 此方式适合执行一些临时性的简单任务

Playbook剧本:
- 将需要执行的任务写入剧本文件,看起来简洁清晰
- 剧本文件中可以包含多个任务
- 剧本能够实现流程控制,比如:判断、循环、变量、标签
- 剧本写好后,随时调用剧本,执行相关的任务
- 适用于经常执行的复杂任务
- 剧本提供语法检查以及模拟执行功能

Playbook剧本意义

电影剧本:
	电影名
	场景
	演员
	事件
	   事件1
	   事件2
	   事件3

Ansible剧本:
	剧本名
	被控节点
	管理被控节点时使用的用户
	任务(事件)
	   任务1
	   任务2
	   任务3

2、剧本书写格式

Playbook剧本要求按照YAML格式编写。

2.1 YAML简介

YAML是一个可读性高、用来表达数据序列的格式语言;YAML以数据为中心,重点描述数据的关系和结构。

2.2 YAML格式特点

YAML语法官方文档:https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html

1."#"代表注释,第一行一般为三个横杠表示开头
2.严格的缩进表示层级关系,缩进一般为2个空格
3.缩进必须使用空格,不能使用tab键
4.字符串通常不需要放在引号里,即使字符串中包含空格
5.支持字典,字典以简单的形式表示 key: value;字典也可以使用{}括起来
6.支持列表,列表的内容使用"-"表示;列表也可用[]括起来
7.":"和"-"后面必须要有一个空格
8.跨行数据可以使用">"来换行
9.剧本文件后缀名必须为yaml或yml

3、剧本编写格式

Playbook剧本必不可少的三个部分:name,hosts,tasks。
name 剧本名称
hosts 被控节点,主机或主机组
tasks 要执行的任务

---                             //第一行一般为三个横杠,可以省略
- name: Update web servers      //剧本名称
  hosts: webservers             //被控节点,主机或主机组
  remote_user: root             //管理被控节点时使用哪个用户

  tasks:                        //要执行的任务
  - name: apache_install        //第一个任务的名称
    tags: t1                    //该任务的标签
    yum:                        //该任务使用的模块,也就是该任务要做的事情
      name: httpd               //yum模块的参数,表示httpd包
      state: latest             //yum模块的参数,表示安装最新版
  - name: apache_config_file    //第二个任务的名称
    tags: t2                    //该任务的标签
    template:                   //该任务使用的模块,也就是该任务要做的事情
      src: /srv/httpd.j2        //模块参数
      dest: /etc/httpd.conf     //模块参数

- name: Update db servers       //第二个剧本名称,第二种格式
  hosts: databases
  remote_user: root

  tasks:
  - name: Ensure postgresql is at the latest version
    yum: name=postgresql state=latest
  - name: Ensure that postgresql is started
    service: name=postgresql state=started

剧本编写案例:编写Rsync服务模式剧本

#环境准备,准备好rsync配置文件和密码文件
[root@manager-18 ~/projects/Rsync_configure_project]# ls
rsyncd.conf  rsync.passwd
#编辑剧本文件,将rsync配置流程写入剧本
[root@manager-18 ~/projects/Rsync_configure_project]# vim Rsync_configure_project.yaml 
- name: Rsync_configure
  hosts: backup

  tasks:
  - name: 01_install_rsync
    tags: t1
    yum:
      name: rsync
      state: latest
  - name: 02_copy_config_file
    tags: t2
    copy:
      src: ./rsyncd.conf
      dest: /etc/rsyncd.conf
  - name: 03_rsync_groupadd
    tags: t3
    group:
      name: rsync
      system: yes
  - name: 04_rsync_useradd
    tags: t4
    user:
      name: rsync
      system: yes
      group: rsync
  - name: 05_make_backup_directory
    tags: t5
    file:
      path: /backup
      owner: rsync
      group: rsync
      state: directory
  - name: 06_copy_password_file
    tags: t6
    copy:
      src: ./rsync.passwd
      dest: /etc/rsync.passwd
      mode: 600
  - name: 07_stop_firewalld_service
    tags: t7
    service:
      name: firewalld
      enabled: no
      state: stopped
  - name: 08_close_the_selinux
    tags: t8
    selinux:
      state: disabled
  - name: 09_start_rsyncd_service
    tags: t9
    service:
      name: rsyncd
      state: started

4、剧本执行命令

//命令格式
ansible-playbook [选项] 剧本文件

//选项
-C				//模拟执行
-i				//指定主机清单hosts文件路径,默认是/etc/ansible/hosts
-v				//显示过程,-vv、-vvv更详细
--list-hosts	//查看哪些主机会执行该剧本
--list-tasks	//列出剧本中所有任务
--start-at-task	//指定从剧本中某个任务开始运行
--list-tags		//列出剧本文件中任务中定义的所有tags
-t				//只运行剧本文件中定义的某些tags任务,多个标签用逗号隔开
--skip-tags		//跳过剧本中某些标签的任务

//示例
//执行某剧本
[root@manager-18 ~/projects/Rsync_configure_project]# ansible-playbook Rsync_configure_project.yaml 

//模拟执行某剧本
[root@manager-18 ~/projects/Rsync_configure_project]# ansible-playbook -C Rsync_configure_project.yaml

//查看哪些主机会执行该剧本
[root@manager-18 ~/projects/Rsync_configure_project]# ansible-playbook --list-hosts Rsync_configure_project.yaml 

playbook: Rsync_configure_project.yaml

  play #1 (backup): Rsync configure     TAGS: []
    pattern: [u'backup']
    hosts (1):
      10.0.0.16

//列出剧本中所有任务
[root@manager-18 ~/projects/Rsync_configure_project]# ansible-playbook --list-tasks Rsync_configure_project.yaml 

playbook: Rsync_configure_project.yaml

  play #1 (backup): Rsync configure     TAGS: []
    tasks:
      01 install rsync  TAGS: [t1]
      02 copy config file       TAGS: [t2]
      03 rsync groupadd TAGS: [t3]
      04 rsync useradd  TAGS: [t4]
      05 make backup directory  TAGS: [t5]
      06 copy password file     TAGS: [t6]
      07 stop firewalld service TAGS: [t7]
      08 close the selinux      TAGS: [t8]
      09 start rsyncd service   TAGS: [t9]

//指定从剧本中第7个任务开始运行
[root@manager-18 ~/projects/Rsync_configure_project]# ansible-playbook --start-at-task "07 stop firewalld service" Rsync_configure_project.yaml 

//列出剧本文件中任务中定义的所有tags
[root@manager-18 ~/projects/Rsync_configure_project]# ansible-playbook --list-tags Rsync_configure_project.yaml 

playbook: Rsync_configure_project.yaml

  play #1 (backup): Rsync configure     TAGS: []
      TASK TAGS: [t1, t2, t3, t4, t5, t6, t7, t8, t9]

//只运行剧本文件中定义的tags为t2,t6,t9的任务
[root@manager-18 ~/projects/Rsync_configure_project]# ansible-playbook -t t2,t6,t9 Rsync_configure_project.yaml

//跳过剧本中标签为t3,t4,t5的任务
[root@manager-18 ~/projects/Rsync_configure_project]# ansible-playbook --skip-tags t3,t4,t5 Rsync_configure_project.yaml

5、Ansible变量应用

Ansible支持很多种定义变量的方式;在此简单列举几种,根据优先级排序:
1.Inventory变量
2.Host Facts变量
3.Register变量
4.Playbook变量
5.变量文件

除了以上变量之外还有"命令行定义的变量"和ansible内置的"magic魔法变量"

变量的调用方式:

通过 {{ variable_name }} 调用变量,且变量名前后建议加空格,有时使用 "{{ variable_name }}" 才能生效

5.1 Inventory变量

#Inventory变量就是主机清单配置文件中定义的变量,该变量可以在剧本中被引用

//示例:之前我们在主机清单中定义了ssh远程登录的用户名,我们可以进行调用
[root@manager-18 ~]# vim inventory_variable_test.yml
---
- name: inventory variable test
  hosts: backup

  tasks:
  - name: print
    debug:
      msg: "the ansible_user value is {{ ansible_user }}"
      #var: ansible_user

# debug 模块用于在调试中输出信息
# 参数
msg			#输出指定消息,消息用引号引起来,可调用变量,ansible中调用变量方法为 {{ 变量名 }}
var			#输出指定变量的值,调用变量不需要使用{{ 变量名 }}

[root@manager-18 ~]# ansible-playbook inventory_variable_test.yml 

PLAY [inventory variable test] ******************************************************************************************************

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

TASK [test01] ***********************************************************************************************************************
ok: [10.0.0.16] => {
    "msg": "the ansible_user value is 172.16.1.16"
}

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

5.2 Host Facts变量

#事实变量就是setup模块获取到的被控节点的主机信息

#示例一
[root@manager-18 ~]# vim facts_variable_test.yml
---
- name: facts variable test
  hosts: backup

  tasks:
  - name: print
    debug:
      msg: "the backup host ip address is {{ ansible_ens33.ipv4.address }}"

[root@manager-18 ~]# ansible-playbook facts_variable_test.yml 

PLAY [facts variable test] **********************************************************************************************************

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

TASK [test01] ***********************************************************************************************************************
ok: [10.0.0.16] => {
    "msg": "the backup host ip address is 172.16.1.16"
}

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


#示例二
[root@manager-18 ~]# vim facts_variable_test.yml
---
- name: facts variable test
  hosts: backup

  tasks:
  - name: test01
    shell: echo "{{ ansible_ens33.ipv4.address }}" > /tmp/{{ ansible_ens33.ipv4.address }}

[root@manager-18 ~]# ansible-playbook facts_variable_test.yml 

PLAY [facts variable test] **********************************************************************************************************

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

TASK [test01] ***********************************************************************************************************************
changed: [10.0.0.16]

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

[root@backup-16 ~]# cat /tmp/172.16.1.16 
172.16.1.16

#注意:若使用不到事实变量,可以关闭获取被控主机的事实变量
# 配置如下:
---
- name: facts variable test
  hosts: backup
  gather_facts: false

5.3 Register变量

#register语句可以将某个命令的执行结果保存至某变量中,该变量就是注册变量

#示例
[root@manager-18 ~]# vim register_variable_test.yml
---
- name: register variable test
  hosts: backup

  tasks:
  - name: test01
    shell: echo "hello world"
    register: hi        #将此任务的结果保存到一个名为"hi"的变量中
  - name: print
    debug:
      var: hi           #在此使用debug模块,输出hi变量内容
      #var: hi.stdout   #输出hi变量中stdout该部分内容

[root@manager-18 ~]# ansible-playbook register_variable_test.yml 

PLAY [register variable test] *******************************************************************************************************

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

TASK [test01] ***********************************************************************************************************************
changed: [10.0.0.16]

TASK [debug] ************************************************************************************************************************
ok: [10.0.0.16] => {
    "hi": {
        "changed": true, 
        "cmd": "echo \"hello world\"", 
        "delta": "0:00:00.002149", 
        "end": "2021-12-03 11:12:50.385688", 
        "failed": false, 
        "rc": 0, 
        "start": "2021-12-03 11:12:50.383539", 
        "stderr": "", 
        "stderr_lines": [], 
        "stdout": "hello world", 
        "stdout_lines": [
            "hello world"
        ]
    }
}

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

5.4 Playbook变量

#在剧本中可以使用vars关键词进行自定义变量

#示例
[root@manager-18 ~]# vim playbook_variable_test.yml
---
- name: playbook variable test
  hosts: backup
  vars:               #在playbook中定义变量
    firstname: han    #第一个变量和值
    lastname: zhuang  #第二个变量和值

  tasks:
  - name: print
    debug:
      msg: "my name is {{ firstname }} {{ lastname }}"

[root@manager-18 ~]# ansible-playbook playbook_variable_test.yml 

PLAY [playbook variable test] *******************************************************************************************************

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

TASK [print] ************************************************************************************************************************
ok: [10.0.0.16] => {
    "msg": "my name is han zhuang"
}

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

#vars_prompt语句可以定义变量的值在剧本运行时手动输入

#示例
[root@manager-18 ~]# vim playbook_vars_prompt_test.yml
---
- name: vars prompt test
  hosts: backup
  gather_facts: false          #关闭事实变量获取
  vars_prompt:                 #定义提示变量
    - name: login_username     #变量名称
      prompt: "please input login username: "    #变量输入提示语
      private: no              #不隐藏输入值
    - name: login_passwd       #第二个变量的名称
      prompt: "please input user password: "     #变量输入提示语
      private: yes             #隐藏输入值

  tasks:
  - name: print
    debug:
      msg: "username is {{ login_username }} , password is {{ login_passwd }}"

[root@manager-18 ~]# ansible-playbook playbook_vars_prompt_test.yml 
please input login username: : hzz      #提示输入变量的值
please input user password: :           #提示输入变量的值,输入的值不显示

PLAY [vars prompt test] *************************************************************************************************************

TASK [print] ************************************************************************************************************************
ok: [10.0.0.16] => {
    "msg": "username is hzz , password is 123456"
}

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

5.5 变量文件

#单独定义一个变量文件,在playbook中用vars_files调用该文件

#示例,创建变量文件,在剧本中引入变量文件
[root@manager-18 ~]# vim /etc/ansible/vartables.yml
---
login_username: hzz
login_passwd: 123456

[root@manager-18 ~]# vim varsfile_variable_test.yml
---
- name: vars prompt test
  hosts: backup
  gather_facts: false
  vars_files: /etc/ansible/vartables.yml    #引入变量文件

  tasks:
  - name: print
    debug:
      msg: "username is {{ login_username }} , password is {{ login_passwd }}"

[root@manager-18 ~]# ansible-playbook varsfile_variable_test.yml 

PLAY [vars prompt test] *************************************************************************************************************

TASK [print] ************************************************************************************************************************
ok: [10.0.0.16] => {
    "msg": "username is hzz , password is 123456"
}

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

5.6 magic魔法变量

Ansible默认会提供一些内置的变量以实现一些特定的功能,我们称之为魔法变量。

变量名称含义
hostvars用于获取某台指定的主机的相关变量
inventory_hostname当前正在运行task的主机的IP或主机名
groupsinventory中所有主机组的列表
group_names当前正在执行task的目标主机位于的主机组
play_hosts当前playbook会在哪些hosts上运行
inventory_dir主机清单所在目录
inventory_file主机清单文件
......

6、剧本高级特性

6.1 触发器语句

notify和handlers语句用于流程控制;notify语句在任务结束时,会根据条件触发,若任务执行后结果有变化则会触发notify。handlers语句中的定义的任务在notify被触发后会被执行;在书写时handlers与tasks同级。

notify和handlers官方文档:https://docs.ansible.com/ansible/latest/user_guide/playbooks_handlers.html

#示例一,Rsync服务模式剧本优化
#剧本执行时,若配置文件已经存在且内容一致,则rsyncd服务则不会重启,若配置文件被更改,则会重启rsyncd服务
[root@manager-18 ~/projects/Rsync_configure_project]# ls
Rsync_configure_project.yaml  rsyncd.conf  rsync.passwd

[root@manager-18 ~/projects/Rsync_configure_project]# vim Rsync_configure_project.yaml 
- name: Rsync configure
  hosts: backup

  tasks:
  - name: 01_install_rsync
    tags: t1
    yum:
      name: rsync
      state: latest
  - name: 02_copy_config_file
    tags: t2
    copy:
      src: ./rsyncd.conf
      dest: /etc/rsyncd.conf
    notify: restart_rsyncd        ##若该任务执行后结果有变化,则触发notify,转而执行handlers中定义的任务
  - name: 03_rsync_groupadd
    tags: t3
    group:
      name: rsync
      system: yes
  - name: 04_rsync_useradd
    tags: t4
    user:
      name: rsync
      system: yes
      group: rsync
  - name: 05_make_backup_directory
    tags: t5
    file:
      path: /backup
      owner: rsync
      group: rsync
      state: directory
  - name: 06_copy_password_file
    tags: t6
    copy:
      src: ./rsync.passwd
      dest: /etc/rsync.passwd
      mode: 600
    notify: restart_rsyncd        ##若该任务执行后结果有变化,则触发notify,转而执行handlers中定义的任务
  - name: 07_stop_firewalld_service
    tags: t7
    service:
      name: firewalld
      enabled: no
      state: stopped
  - name: 08_close_the_selinux
    tags: t8
    selinux:
      state: disabled

  handlers:
  - name: restart_rsyncd
    service:
      name: rsyncd
      state: restarted

#示例二
#触发notify,执行多个handlers中定义的任务
- name: Template configuration file
  template:
    src: template.j2
    dest: /etc/foo.conf
  notify:
    - Restart memcached
    - Restart apache

  handlers:
    - name: Restart memcached
      service:
        name: memcached
        state: restarted
    - name: Restart apache
      service:
        name: apache
        state: restarted

#handlers中定义的任务会在所有任务执行完毕后再执行,避免handlers中定义的任务被重复执行;handlers中的任务也可以自己监听notify的触发
handlers:
  - name: Restart memcached
    service:
      name: memcached
      state: restarted
    listen: "restart web services"

  - name: Restart apache
    service:
      name: apache
      state: restarted
    listen: "restart web services"

tasks:
  - name: Restart everything
    command: echo "this task will restart the web services"
    notify: "restart web services"

6.2 剧本文件复用

剧本中可以导入其他剧本,若有一些基础的任务,可以单独写一个剧本,然后在其他剧本中导入调用。

剧本文件复用官方文档:https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse.html

导入方式 特点
include_*动态导入,包括角色、任务或变量,将它们动态添加到剧本中。导入的任务可能会受到顶级剧本中较早任务结果的影响。官方说已弃用
import_*静态导入,导入角色、任务或剧本会将它们静态添加到剧本中;在运行剧本中的任何任务之前对导入的文件和角色进行预处理,因此导入的内容永远不会受到顶级剧本中其他任务的影响。预处理导入时变量必须可用,变量需要提前定义。
#示例,Rsync服务模式剧本再次优化
[root@manager-18 ~/projects/Rsync_configure_project]# vim Firewalld_selinux_stop.yaml
- name: Firewalld_selinux_stop
  hosts: all

  tasks:
  - name: 01_stop_firewalld_service
    tags: t1
    service:
      name: firewalld
      enabled: no
      state: stopped
  - name: 02_close_the_selinux
    tags: t2
    selinux:
      state: disabled

[root@manager-18 ~/projects/Rsync_configure_project]# vim Rsync_configure_project.yaml
- import_playbook: Firewalld_selinux_stop.yaml    #引入前面的关闭防火墙和selinux剧本
- name: Rsync_configure
  hosts: backup

  tasks:
  - name: 01_install_rsync
    tags: t1
    yum:
      name: rsync
      state: latest
  - name: 02_copy_config_file
    tags: t2
    copy:
      src: ./rsyncd.conf
      dest: /etc/rsyncd.conf
    notify: restart_rsyncd
  - name: 03_rsync_groupadd
    tags: t3
    group:
      name: rsync
      system: yes
  - name: 04_rsync_useradd
    tags: t4
    user:
      name: rsync
      system: yes
      group: rsync
  - name: 05_make_backup_directory
    tags: t5
    file:
      path: /backup
      owner: rsync
      group: rsync
      state: directory
  - name: 06_copy_password_file
    tags: t6
    copy:
      src: ./rsync.passwd
      dest: /etc/rsync.passwd
      mode: 600
    notify: restart_rsyncd

  handlers:
  - name: restart_rsyncd
    service:
      name: rsyncd
      state: restarted

#示例二,如果要在剧本中多次运行导入的剧本,若导入的剧本中存在变量,则必须定义好变量
tasks:
- import_tasks: wordpress.yml
  vars:
    wp_user: timmy

- import_tasks: wordpress.yml
  vars:
    wp_user: alice

- import_tasks: wordpress.yml
  vars:
    wp_user: bob

6.3 剧本循环语句

循环语句用于多次执行任务,当某些任务需要多次执行时使用循环语句,例如:创建多个用户。

循环语句官方文档:https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html

#示例一:Loop循环列表内容,创建多个用户
[root@manager-18 ~]# vim useradd_test.yml
---
- name: create user
  hosts: dev

  tasks:
    - name: create user
      user:
        name: "{{ item }}"
        state: present
      loop:
      - user01
      - user02
      - user03
    - name: set password
      shell: echo '12345678' | passwd --stdin "{{ item }}"
      loop:
      - user01
      - user02
      - user03

#示例二:vars变量传递列表内容给Loop循环
[root@manager-18 ~]# vim useradd_test_v2.yml
---
- name: create user
  hosts: dev
  vars:
     users:
      - user01
      - user02
      - user03

  tasks:
    - name: create user
      user:
        name: "{{ item }}"
        state: present
      loop: "{{ users }}"

    - name: set password
      shell: echo '12345678' | passwd --stdin "{{ item }}"
      loop: "{{ users }}"

#示例三:哈希列表Loop循环
[root@manager-18 ~]# vim useradd_test_v3.yml
---
- name: create user
  hosts: dev

  tasks: 
  - name: create user and group
    user:
        name: "{{ item.name }}"
        group: "{{ item.groups }}"
    loop:
    - {name: 'user01', groups: 'wheel'}
    - {name: 'user02', groups: 'root'}

#示例四:vars变量传递哈希列表给Loop循环
[root@manager-18 ~]# vim useradd_test_v4.yml
---
- name: loop test
  hosts: dev
  vars:
    users:
    - user: 'user01'
      group: 'wheel'
    - user: 'user02'
      group: 'root'

  tasks:
    - name: debug
      user:
        name: "{{ item.user }}"
        group: "{{ item.group }}"
      loop: "{{ users }}"  

#示例五:vars变量传递字典给Loop循环,并使用dict filter(字典过滤器)
[root@manager-18 ~]# vim useradd_test_v5.yml
---
- name: loop test
  hosts: dev
  vars:
    users:
      user: 'user01'
      groups: 'root'

  tasks:
    - name: debug
      debug:
        msg: "{{ item.key }}  {{ item.value }}"
      loop: "{{ users|dict2items }}"        # |表示过滤器,|dict2items字典过滤器;users变量中的值传递给字典过滤器,字典过滤器将内容过滤为key,value的格式

#转换之前的格式
  vars:
    users:
      user: 'user01'
      groups: 'root'

#转换之后的格式
    - key: user
      value: user01
    - key: groups
      value: root

6.4 条件判断语句

when语句用于条件判断,当任务需要在某些特定情况下执行的话,我们就需要进行判断,当判断结果为真时执行此任务,当判断结果为假则不执行此任务。

when语句官方文档:https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html

比较符、逻辑运算符、其他符号含义
==比较两个对象是否相等
!=比较两个对象是否不等
>比较左侧对象是否大于右侧
>=比较左侧对象是否大于等于右侧
<比较左侧对象是否小于右侧
<=比较左侧对象是否小于等于右侧
and如果前后条件都为为真,则返回真
or如果前后条件有一个为真,则返回真
not取反
()括号对判断条件进行分组
变量 is defined某变量已经定义
变量 is not defined某变量未定义
注册变量 is succeeded注册变量结果为真
注册变量 is failed注册变量结果为假
注册变量 is skipped注册变量结果为跳过
变量 in 列表/字典某变量在某字典或列表中存储
#示例一
[root@manager-18 ~]# vim test.yml
---
- name: test
  hosts: web

  tasks:
  - name: test01
    debug:
      msg: "this is centos"
    when: ansible_distribution == "CentOS"
  - name: test02
    debug:
      msg: "this is redhat"
    when: ansible_distribution == "RedHat"

#示例二,当有多个判断条件时使用()将条件进行分组,分组后使用逻辑运算符
[root@manager-18 ~]# vim test.yml
---
- name: test
  hosts: web

  tasks:
  - name: test01
    debug:
      msg: "this is centos7"
    when: (ansible_distribution == "CentOS") and
          (ansible_distribution_major_version == "7")


#示例三,当有多个判断条件并且逻辑运算符为 and 时,可写为列表格式
[root@manager-18 ~]# vim test.yml
---
- name: test
  hosts: web

  tasks:
  - name: test01
    debug:
      msg: "this is centos7"
    when:
      - ansible_distribution == "CentOS"
      - ansible_distribution_major_version == "7"

#示例四,在循环中使用条件判断语句
[root@manager-18 ~]# vim test.yml
---
- name: test
  hosts: web

tasks:
    - name: Run with items greater than 5
      command: echo {{ item }}
      loop: [ 0, 2, 4, 6, 8, 10 ]
      when: item > 5

#示例五,在循环中使用条件判断语句
[root@manager-18 ~]# vim test.yml
- name: install mariadb-server if enough space
  yum:
    name: mariadb-server
    state: latest
  loop: "{{ ansible_mounts }}"         #循环事实变量,ansible_mounts表示磁盘挂载信息
  when: item.mount == "/" and item.size_available > 300000000    #判断"/"挂载点大小大于300M

#示例六,判断变量是否定义
[root@manager-18 ~]# vim test.yml
- name: test
  hosts: backup
  vars:
    hzz: 123

  tasks:
  - name: test01
    debug:
      msg: The variable is defined
    when: hzz is defined
  - name: test02
    debug:
      msg: The variable is undefined
    when: hzz is undefined


#示例七,判断注册变量结果
[root@manager-18 ~]# vim test.yml
- name: test
  hosts: backup
  ignore_errors: true

  tasks:
  - name: test01
    shell: echo1 "123"
    register: hzz
  - name: test02
    debug:
      msg: The result is succeeded
    when: hzz is succeeded
  - name: test03
    debug:
      msg: The result is failed
    when: hzz is failed

#示例八,
[root@manager-18 ~]# vim test.yml
- name: test
  hosts: backup
  ignore_errors: True

  tasks:
  - name: Statistical process
    shell: ps -ef | grep httpd | wc -l
    register: check_value
  - name: Print information
    debug:
      msg: echo "Process already exists"
    when: check_value.stdout|int > 0        #剧本中使用|过滤器,将注册变量输出的值转换为int类型再进行判断是否大于0

6.5 失败任务处理

ignore_errors语句用于忽略剧本任务中错误的命令。

ignore_errors语句官方文档:https://docs.ansible.com/ansible/latest/user_guide/playbooks_error_handling.html

#示例一
#编写一个测试剧本,故意写错剧本任务
[root@manager-18 ~]# vim error.yml
---
- name: error test
  hosts: backup

  tasks:
  - name: 01 test
    service:
      name: test    #没有此服务,运行该剧本会报错,后面的任务将不会执行
      state: started
  - name: 02 test
    file:
      path: /tmp/testfile
      state: touch

#忽略剧本中某任务的报错,使剧本继续运行
[root@manager-18 ~]# vim error.yml
---
- name: error test
  hosts: backup

  tasks:
  - name: 01 test
    service:
      name: test
      state: started
    ignore_errors: true    #在此任务中加入ignore_errors,忽略该任务的错误
  - name: 02 test
    file:
      path: /tmp/testfile
      state: touch

#示例二
#忽略剧本中所有报错,使剧本继续运行
[root@manager-18 ~]# vim error.yml
---
- name: error test
  hosts: backup
  ignore_errors: true    #将ignore_errors中加入剧本全局配置,忽略剧本中所有错误

  tasks:
  - name: 01 test
    service:
      name: test
      state: started
  - name: 02 test
    file:
      path: /tmp/testfile
      state: touch

6.6 template模板

template模板是一个文本文件主要作为生成所需文件的模板,模板文件中可以调用变量、嵌套jinja语法;ansible中template模块专门用于传输模板文件;模板文件后缀名为.j2。

jinja2语言:

jinja2是Python的全功能模板引擎。

jinja语言官方文档:https://jinja.palletsprojects.com/en/2.11.x/templates/

jinja2语言支持的特性:
字符串:使用单引号或双引号
数字:整数,浮点数
列表:[item1, item2, ...]
元组:(item1, item2, ...)
字典:{key1:value1, key2:value2,...}
布尔型:true/false
算术运算符:+,-,*,/,//,%,**
比较符:==,!=,>,>=,<,<=
逻辑运算符:and,or,not
其他运算符:in,is,|
表达式:for,if,when
():括号中的内容为一组表达式
{{}}:两对花括号用于调用变量

template模块:

template模块用法与copy模块用法类似,但template模块传输的文件中可写入jinja语法,写入的jinja语法会被template模块识别处理。

//template模块参数
src			//控制节点源文件
dest		//传输至被控节点后文件存放位置
owner		//指定属主
group		//指定属组
mode		//指定权限
backup		//是否备份

template模板应用示例:

#示例一
#先创建好nginx配置文件模板,模板中使用变量替换配置文件内容;内容如下
[root@manager-18 ~]# vim nginx.conf.j2 
user  nginx;
worker_processes  {{ ansible_processor_vcpus }};    #此处在模板文件中使用事实变量,配置文件更加灵活

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;
.....
.....

#编写nginx服务部署剧本,使用模板文件
[root@manager-18 ~]# vim nginx_config.yml
---
- name: nginx_config
  hosts: web
  vars: 
    nginx_vhosts:
      - listen: 80
      - listen: 8080

  tasks:
  - name: check_nginx_repo_exists
    stat:
      path: /etc/yum.repos.d/nginx.repo
    ignore_errors: true
    register: nginx_repo_file_status
  - name: yum_config
    copy:
      src: ./nginx.repo
      dest: /etc/yum.repos.d/nginx.repo
    when: nginx_repo_file_status.stat.exists == false
  - name: yum_install_nginx
    yum:
      name: nginx
      state: latest
  - name: copy_nginx_config
    template:
      src: ./nginx.conf.j2
      dest: /etc/nginx/nginx.conf
      backup: yes
    notify: restart_nginx

  handlers:
    - name: restart_nginx
      service:
        name: nginx
        state: restarted
        enabled: yes


#改:nginx配置文件模板中也可使用算数运算
[root@manager-18 ~]# vim nginx.conf.j2 
user  nginx;
worker_processes  {{ ansible_processor_vcpus*3 }};    #此处在模板文件中使用事实变量和运算符

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;
.....
.....

#示例二
#nginx配置文件模板中使用for循环
[root@manager-18 ~]# vim nginx.conf.j2 
.....
.....
server {
  {% for vhost_port in nginx_vhosts %}
    listen {{ vhost_port.listen }};
  {% endfor %}
    server_name  localhost;
.....
.....

#示例三
#nginx配置文件模板中使用if判断
[root@manager-18 ~]# vim nginx.conf.j2 
.....
.....
server {
  {% for vhost_port in nginx_vhosts %}
    listen {{ vhost_port.listen }};
  {% endfor %}

  {% if ansible_default_ipv4.address=="10.0.0.12"  %}
    server_name  web12.hzz.com;
  {% endif %}

  {% if ansible_default_ipv4.address=="10.0.0.13"  %}
    server_name  web13.hzz.com;
  {% endif %}

  {% if ansible_default_ipv4.address=="10.0.0.14"  %}
    server_name  web14.hzz.com;
  {% endif %}
.....
.....

#示例四
[root@manager-18 ~]# vim nginx.conf.j2 
.....
.....
server {
  {% for vhost_port in nginx_vhosts %}
    listen {{ vhost_port.listen }};
  {% endfor %}

{% if ansible_default_ipv4.address is defined %}         #判断变量是否被定义
  {% if ansible_default_ipv4.address=="10.0.0.12"  %}
    server_name  web12.hzz.com;
  {% endif %}

  {% if ansible_default_ipv4.address=="10.0.0.13"  %}
    server_name  web13.hzz.com;
  {% endif %}

  {% if ansible_default_ipv4.address=="10.0.0.14"  %}
    server_name  web14.hzz.com;
  {% endif %}
{% endif %}
.....
.....
鄂ICP备19026312号-1