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或主机名
groups inventory中所有主机组的列表
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 %}
.....
.....