ansible使用笔记(三)Jinja2模板及playbook简介

ansible playbook编写

目录
一、Jinja2模板简介
二、playbook简介
三、playbook编写
四、playbook进阶

  • 4.1 变量
  • 4.2 error处理
  • 4.3 tags标签
  • 4.4 handlers
  • 4.5 when条件判断
  • 4.6 register返回值
  • 4.7 with_items 循环
  • 4.8 include
  • 4.9 debug调试

一、Jinja2模板简介
Jinja2是什么
Jinja2是基于Python的模板引擎,包含变量和表达式两部分,两者在模板求值时会被替换为值,模板中还有标签,控制模板的逻辑

为什么要学习Jinja2模板
因为playbook的模板使用Python的Jinja2模块来处理

Jinja2模版的基本语法

  • 模板的表达式都是包含在他要分隔符"{{}}"内的
  • 控制的语句都是包含在分隔符"{% %}"内的
  • 模板支持注释,都是包含在分隔符'{# #}'内,支持块注释
  • 调用变量
    {{varname}}
  • 计算
    {{2+2}}
  • 判断
    {{1 in {{1,2,3}}
  • Jinja2模版控制语句
{% if name == '诗仙' %}
  李白
{% elif name == '诗圣' %}
  杜甫
{% elif name == '诗魔' %}
  白居易
{% else %}
  李贺
{% endif %}

Jinja2过滤器
变量可以通过过滤器修改,过滤器与变量用管道符号( | )分割,也可以用圆括号传递可选参数,多个过滤器可以链式调用,前一个过滤器的输出会被作业后一个过滤器的输入

例如:
加密一个字符串:{{'astr'|password_hash('sha512')}}

二、playbook简介
playbook是什么
playbook是ansible用于配置,部署和管理托管主机剧本,通过playbook的详细描述,执行其中一系列tasks,可以让远端主机达到预期的状态

也可以说 playbook字面意思即剧本,现实中由演员按剧本表演,在ansible中由计算机进行安装,部署应用,提供对外服务,以及组织计算机处理各种各样的事情

为什么要使用palybook

  • 执行一些简单的任务,使用ad-hoc命令可以方便的解决问题,但有时一个设施过于复杂时,执行ad-hoc命令是不合适的,最好使用playbook

  • playbook可以反复使用编写的代码,可以放到不同机器上面,像函数一样,最大化的利用代码,在使用ansible的过程中,处理的大部分操作都是在编写playbook

playbook语法基础(1)

  • playbook由YAML语文编写,遵循YAML标准
  • 在同一行中,#之后的内容表示注释
  • 同一个列表中元素应该保持相同缩进
  • playbook由一个或多个play组成
  • play中host,variables,roles,tasks等对角表示方法都是键值中间以": "分隔表示
  • YAML还有一个小的怪癖,它的文件开始行都是以 ---,这是YAML格式的一部分,表明一个文件的开始

playbook构成

  • hosts: 定义交要执行playbook的远程主机级
  • vars: 定义playbook运行时需要使用的变量
  • tasks: 定义将要远程主机上执行的任务列表
  • handlers: 定义task执行完成以后需要调用的任务

playbook执行结果
使用ansible-playbook运行playbook文件,输出内容为JSON格式,由不同颜色组成便于识别

  • 绿色代表执行成功
  • 黄色 代表系统状态发生改变
  • 红色代表执行失败

ansible具有幂等性,幂等性能够保证我们重复的执行一项操作时,得到的结果是相同的,我们再来回顾一下幂等性的概念

"幂等性"是什么意思呢?举个例子,你想把一个文件拷贝到目标主机的某个目录上,但是你不确定此目录中是否已经存在此文件,当你使用ansible完成这项任务时,就非常简单了,因为如果目标主机的对应目录中已经存在此文件,那么ansible则不会进行任何操作,如果目标主机的对应目录中并不存在此文件,ansible就会将文件拷贝到对应目录中,说白了,ansible是"以结果为导向的",我们指定了一个"目标状态",ansible会自动判断,"当前状态"是否与"目标状态"一致,如果一致,则不进行任何操作,如果不一致,那么就将"当前状态"变成"目标状态",这就是"幂等性","幂等性"可以保证我们重复的执行同一项操作时,得到的结果是一样的。

有了幂等性的概念上面显示颜色代表的不同结果就比较好理解了

  • 绿色 代表执行成功 结果已经和指定"目标状态"一致不需要修改
  • 黄色 执行成功,系统状态发生改变,修改过"目标状态"
  • 红色代表执行失败

三、playbook编写
使用ping模块编写 第一个playbook

[root@ansible default]# cat ping.yml 
---                   #第一行,表示开始
- hosts: all          #远程主机,多个可以用逗号孙隔开
  remote_user: root   #远程执行的用户名
  tasks:
  - name: ping test   #任务名称,你也可以理解为备注信息,会在执行中显示,方便阅读
    ping:             #模块名ping

[root@ansible default]# ansible-playbook ping.yml -f 5    #-f 并发进程数量,默认是5

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

TASK [Gathering Facts] ******************************************************************************
ok: [cache]
ok: [web1]
ok: [web2]
ok: [db2]
ok: [db1]

TASK [ping test] ************************************************************************************
ok: [cache]
ok: [web1]
ok: [web2]
ok: [db1]
ok: [db2]

PLAY RECAP ******************************************************************************************
cache                      : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
db1                        : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
db2                        : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
web1                       : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
web2                       : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

playbook语法基础(2)

  • tasks
    命令的集合
    每一个play包含一个task列表(任务列表)
    一个task在其所对应的所有主机上(通过hosts pattern匹配的所有主机) 执行完毕之后,下一个task才执行
  • hosts
    主机的集合
    定义要执行的主机

案例1:
实现 给web主机添加用户james
设置默认密码123456,并把james用户添加到users组

[root@ansible default]# cat user.yml 
---
- hosts: web
  remote_user: root
  tasks:
    - name: Add the user 'james'
      user:
        name: james
        groups: users 
    - name: set passwd
      shell: echo 123456|passwd --stdin james

[root@ansible default]# ansible-playbook user.yml 

PLAY [web] ******************************************************************************************

TASK [Gathering Facts] ******************************************************************************
ok: [web1]
ok: [web2]

TASK [Add the user 'james'] *************************************************************************
changed: [web1]
changed: [web2]

TASK [set passwd] ***********************************************************************************
changed: [web2]
changed: [web1]

PLAY RECAP ******************************************************************************************
web1                       : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
web2                       : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0

案例2:
要求:
1.所以web主机安装Apache
2.修改配置文件的监听端口为8080
3.设置默认页面hello world
4.启动服务
5.设置开机自启

1) 先在本面准备默认访问

[root@ansible default]# cat /root/index.htm
hello world

2)编号playbook

[root@ansible default]# cat http.yml 
---
- hosts: web
  remote_user: root
  tasks:                                         
     - name: install one specific version of Apache   //tasks01.安装 
       yum:
         name: httpd
         state: installed
     - lineinfile:                               //tasks02.修改监听端口
           path: /etc/httpd/conf/httpd.conf
           regexp: '^Listen'
           line: 'Listen 8080'
     - copy:                                  //tasks03替换主页index.html
         src: /root/index.html
         dest: /var/www/html/index.html
     - service:                             //tasks04.开启服务 
         name: httpd
         enabled: yes
         state: restarted
[root@ansible default]# ansible-playbook http.yml 

PLAY [web] ***********************************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************************
ok: [web1]
ok: [web2]

TASK [install one specific version of Apache] ************************************************************************************

changed: [web2]
changed: [web1]

TASK [lineinfile] ****************************************************************************************************************
changed: [web1]
changed: [web2]

TASK [copy] **********************************************************************************************************************
changed: [web2]
changed: [web1]

TASK [service] *******************************************************************************************************************
changed: [web2]
changed: [web1]

PLAY RECAP ***********************************************************************************************************************
web1                       : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
web2                       : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[root@ansible default]# curl web1:8080    //测试
holle world

四、playbook进阶
4.1 变量
案例3:

要求:添加用户 使用变量username代替
给web主机添加用户james2,设置默认密码123456

[root@ansible default]# cat user2.yml 
---
- hosts: web
  remote_user: root
  vars:
    username: james2
  tasks:
    -
      name: Add the user  "{{username}}"
      user: 
        name: "{{username}}"
    -
      shell: echo 123456|passwd --stdin "{{username}}"

[root@ansible default]# ansible-playbook user2.yml 

PLAY [web] ************************

......

用户设密码
作完以上的实验你肯定已经发现为什么不用user模块直接设置密码,而且用shell模块单独设置,这是因为user模块是把Password字符串直接写入shadow,并没有改变,而Linux的shadow密码是经过加密的,所以明文密码不能直接使用

解决方案
-使用变量过滤器password_hash
{{'urpassword'|password_hash('sha512')}}

最后的playbook如下

[root@ansible default]# cat user3.yml 
---
- hosts: web
  remote_user: root
  vars:
    username: james2
  tasks:
    - name: Add the user "{{username}}"
      user: 
        name: "{{username}}"
        group: root
        password: "{{'123qqq...A'|password_hash('sha512')}}"

变量参数
-e 传递变量或文件参数
-e @文件
文件的格式必须是YAML或JSON格式

[root@ansible default]# ansible-playbook user3.yml -e username=james4

PLAY [web] *******************************************************************************************

TASK [Gathering Facts] *******************************************************************************
ok: [web2]
ok: [web1]

TASK [Add the user "james4"] *************************************************************************
changed: [web2]
changed: [web1]

PLAY RECAP *******************************************************************************************
web1                       : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0 
web2                       : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0 

[root@ansible default]# ssh web1 id james4
uid=1007(james4) gid=0(root) 组=0(root)

[root@ansible default]# cat username.yml 
---
username:
  james5

[root@ansible default]# ansible-playbook user3.yml -e @username.yml

PLAY [web] ******************************************************************************************

TASK [Gathering Facts] ******************************************************************************
ok: [web1]
ok: [web2]

TASK [Add the user "james5"] ************************************************************************
changed: [web2]
changed: [web1]

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

[root@ansible default]# cat username.yml 
---
username:
  james5
[root@ansible default]# ssh web1 id james5
uid=1008(james5) gid=0(root) 组=0(root)

4.2 error 处理 ansible-playbook对错误的处理
因为playbook是顺序执行,当遇到错误就会停止往下执行,默认情况判断上一个任务$?,如果值不为0就停止执行
但某些情况我们需要忽略错误继续执行

案例4:
要求:
创建缓存目录,然后重启 apache
1.因为 /tmp/web 之前已经存在 shell模块 mkdir报错playbook停止继续执行,但其实这个错误是不影响下面的任务执行

[root@ansible default]# cat Restart.yml 
---
- hosts: web
  remote_user: root
  tasks:
  - shell: mkdir /tmp/web
  - name: ReStart service httpd
    service:
      name: httpd
      state: restarted

[root@ansible default]# ansible-playbook Restart.yml 

PLAY [web] ******************************************************************************************

TASK [Gathering Facts] ******************************************************************************
ok: [web2]
ok: [web1]

TASK [shell] ****************************************************************************************
[WARNING]: Consider using the file module with state=directory rather than running 'mkdir'.  If you
need to use command because file is insufficient you can add 'warn: false' to this command task or
set 'command_warnings=False' in ansible.cfg to get rid of this message.
fatal: [web2]: FAILED! => {"changed": true, "cmd": "mkdir /tmp/web", "delta": "0:00:00.008765", "end": "2020-11-19 16:55:04.967697", "msg": "non-zero return code", "rc": 1, "start": "2020-11-19 16:55:04.958932", "stderr": "mkdir: 无法创建目录\"/tmp/web\": 文件已存在", "stderr_lines": ["mkdir: 无法创建目录\"/tmp/web\": 文件已存在"], "stdout": "", "stdout_lines": []}
fatal: [web1]: FAILED! => {"changed": true, "cmd": "mkdir /tmp/web", "delta": "0:00:00.007319", "end": "2020-11-19 16:55:05.751981", "msg": "non-zero return code", "rc": 1, "start": "2020-11-19 16:55:05.744662", "stderr": "mkdir: 无法创建目录\"/tmp/web\": 文件已存在", "stderr_lines": ["mkdir: 无法创建目录\"/tmp/web\": 文件已存在"], "stdout": "", "stdout_lines": []}

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

错误处理方法:
添加错误选项:ignore_errors
True 表示忽略错误继续执行
False 表示遇到错误就停止执行(默认)

[root@ansible default]# cat Restart.yml 
---
- hosts: web
  remote_user: root
  tasks:
  - shell: mkdir /tmp/web
    ignore_errors: True
  - name: ReStart service httpd
    service:
      name: httpd
      state: restarted

[root@ansible default]# ansible-playbook Restart.yml 

PLAY [web] ******************************************************************************************

TASK [Gathering Facts] ******************************************************************************
ok: [web1]
ok: [web2]

TASK [shell] ****************************************************************************************
[WARNING]: Consider using the file module with state=directory rather than running 'mkdir'.  If you
need to use command because file is insufficient you can add 'warn: false' to this command task or
set 'command_warnings=False' in ansible.cfg to get rid of this message.
fatal: [web2]: FAILED! => {"changed": true, "cmd": "mkdir /tmp/web", "delta": "0:00:00.007426", "end": "2020-11-19 17:01:57.077906", "msg": "non-zero return code", "rc": 1, "start": "2020-11-19 17:01:57.070480", "stderr": "mkdir: 无法创建目录\"/tmp/web\": 文件已存在", "stderr_lines": ["mkdir: 无法创建目录\"/tmp/web\": 文件已存在"], "stdout": "", "stdout_lines": []}
...ignoring
fatal: [web1]: FAILED! => {"changed": true, "cmd": "mkdir /tmp/web", "delta": "0:00:00.014932", "end": "2020-11-19 17:01:57.853702", "msg": "non-zero return code", "rc": 1, "start": "2020-11-19 17:01:57.838770", "stderr": "mkdir: 无法创建目录\"/tmp/web\": 文件已存在", "stderr_lines": ["mkdir: 无法创建目录\"/tmp/web\": 文件已存在"], "stdout": "", "stdout_lines": []}
...ignoring

TASK [ReStart service httpd] ************************************************************************
changed: [web2]
changed: [web1]

PLAY RECAP ******************************************************************************************
web1                       : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=1   
web2                       : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=1   

4.3 tags标签
tags:给指定的任务定义一个调用标识 有时把多个模块写在一个playbook中.但只想用到其中一个或其中几个模块

-使用方法在模块里添加tags标签
-playbook调用方式
-t TAGS, --tags=TAGS
案例5:
要求:调用任务 task03 创建文件

[root@ansible default]# cat tags2.yml 
---
- hosts: web
  remote_user: root
  tasks:
    - name: task01
      file:
        path: /tmp/web/task01
        state: touch
      tags: t1
    - name: task02
      file:
        path: /tmp/web/task02
        state: touch
      tags: t2
    - name: task03
      file:
        path: /tmp/web/task03
        state: touch
      tags: t3

[root@ansible default]# ansible-playbook tags2.yml -t t3

PLAY [web] ******************************************************************************************

TASK [Gathering Facts] ******************************************************************************
ok: [web2]
ok: [web1]

TASK [task03] ***************************************************************************************
changed: [web2]
changed: [web1]

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

[root@ansible default]# ssh web1 ls /tmp/web/
task03

4.4 handlers
当关注的资源发生变化时采取的操作
notify这个action可用于每个play的最后触发,这样就可以避免有多次改变发生时每次都执行指定的操作,取而代之仅在所有的变化发生完成后一次性执行指定操作

在notify中列出的操作称为handler,即notify调用handler中定义的操作

我们还是拿上面的httpd服务举例
案例6:
要求:
修改httpd 默认index.html 然后重启httpd服务

[root@ansible default]# cat RestartHttp.yml 
---
- hosts: web
  remote_user: root
  tasks:
  - copy:
      src: /root/index.html
      dest: /var/www/html/index.html
    ignore_errors: True
  - name: ReStart service httpd
    service:
      name: httpd
      state: restarted

[root@ansible default]# ansible-playbook RestartHttp.yml 

PLAY [web] *******************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *******************************************************************************************************************************************************************************************
ok: [web1]
ok: [web2]

TASK [copy] ******************************************************************************************************************************************************************************************************
changed: [web2]
changed: [web1]

TASK [ReStart service httpd] *************************************************************************************************************************************************************************************
changed: [web2]
changed: [web1]

PLAY RECAP *******************************************************************************************************************************************************************************************************
web1                       : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
web2                       : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

第二次执行相同操作

[root@ansible default]# ansible-playbook RestartHttp.yml 

第二次和第一次执行的区别是没有在拷贝文件,因为第一次已经拷贝过了,但服务还是重启过两次,看上去好像没问题,但细想第二次文件没有改动过,和我们修改配置文件后重启服务的实际需求是有区别的,或者说第二次服务重次是完全没有必要的

这时就要用的notify调用handler中定义的操作
简单说就是当文件发生过改动后,才重启服务

修改配置后

[root@ansible default]# cat RestartHttp.yml
---
- hosts: web
  remote_user: root
  tasks:
  - copy:
      src: /root/index.html
      dest: /var/www/html/index.html
    ignore_errors: True
    notify:
    - restart "ReStart service httpd"
    
  handlers:
  - name: ReStart service httpd
    service:
      name: httpd
      state: restarted

[root@ansible default]# ansible-playbook RestartHttp.yml 

PLAY [web] ******************************************************************************************

TASK [Gathering Facts] ******************************************************************************
ok: [web2]
ok: [web1]

TASK [copy] *****************************************************************************************
ok: [web1]
ok: [web2]

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

从执行结果来看 并没有重启httpd服务

4.5 when条件判断
有些时候需要在满足特定条件后再触发某一项操作,或在特定的条件下终止某个行为,这时候需要进行条件判断,when正是解决这个问题的最佳选择,行程中的系统变量facts作为when的条件,可以通过setup模块查看

案例7:
我们用debug模块做个测试 debug模块我们后面会讲到
通过两个when判断条件如果成立,则输出"System release is centos7"

[root@ansible default]# cat when.yml 
---
- hosts: cache
  remote_user: root
  tasks:
  - debug:
      msg: "System release is centos7"
    when:
    - ansible_distribution == "CentOS"
    - ansible_distribution_major_version == "7"

[root@ansible default]# ansible-playbook when.yml 

PLAY [cache] ****************************************************************************************

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

TASK [debug] ****************************************************************************************
ok: [cache] => {
    "msg": "System release is centos7"
}

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

4.6 register返回值
有时候我们还需要更复杂的例子,如判断前一个命令的执行结果去处理后面的操作,这时候就需要register模块来保存前一个命令的返回状态,在后面进行调用

案例8:
要求:把系统负载太高的Apache服务停止
当系统负载超过0.7时,则关掉httpd

[root@web2 ~]# awk 'BEGIN{while(1){}}'    //先用awk对web2提高系统负载,为测试创建条件

[root@ansible default]# ssh web2 uptime   //已经满足测试条件
 11:10:11 up 24 days, 17:47,  2 users,  load average: 0.88, 0.30, 0.14

root@all (5)[f:5]$ sys
[root@ansible default]# ansible-console web   //通过ansible-console 查看httpd状态
Welcome to the ansible console.
Type help or ? to list commands.

root@web (2)[f:5]$ systemctl status httpd
web1 | CHANGED | rc=0 >>
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
   Active: active (running) since 四 2020-11-19 17:58:04 CST; 17h ago
......

web2 | CHANGED | rc=0 >>
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
   Active: active (running) since 四 2020-11-19 17:58:03 CST; 17h ago
....

root@web (2)[f:5]$ exit

[root@ansible default]# cat when.yml 
---
- hosts: web
  remote_user: root
  tasks:
  - shell: uptime|awk '{printf("%.2f\n",$(NF-2))}'
    register: result                                      //返回shell执行结果到变量result
  - name: stop  service
    service:
      name: httpd
      state: stopped
    when: result.stdout|float > 0.7                //对result 结果进行判断

[root@ansible default]# ansible-playbook when.yml 

PLAY [web] ******************************************************************************************

TASK [Gathering Facts] ******************************************************************************
ok: [web1]
ok: [web2]

TASK [shell] ****************************************************************************************
changed: [web1]
changed: [web2]

TASK [stop  service] ********************************************************************************
skipping: [web1]
changed: [web2]

PLAY RECAP ******************************************************************************************
web1                       : ok=2    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
web2                       : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[root@ansible default]# ssh web2 systemctl status httpd
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
   Active: inactive (dead) since 五 2020-11-20 11:24:23 CST; 41s ago    //httpd服务已关闭
......

4.7 with_items 循环
with_items是playbook标准循环,可以用于迭代一个列表或字典,通过{{item}}获取每次迭代的值
案例9:
要求:一次性创建多个用户nb、aa、plj、lx

[root@ansible default]# cat adduser.yml 
---
- hosts: cache
  remote_user: root
  tasks:
  - name: add users
    with_items: ["nb","aa","plj","lx"]
    user: group=wheel password={{'123456'|password_hash('sha512')}} name={{item}}
[root@ansible default]# ansible-playbook adduser.yml 

PLAY [cache] ****************************************************************************************

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

TASK [add users] ************************************************************************************
changed: [cache] => (item=nb)
changed: [cache] => (item=aa)
changed: [cache] => (item=plj)
changed: [cache] => (item=lx)

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

4.8 include
在编写playbook的时候随随着项目越来越大,playbook越来越复杂,修改也很麻烦,这时可以把一些paly、task或handler放到其他文件中,通过include指令包含进来是一个不错的选择
包含项包括

  • vars:变量层
  • tasks:任务层
  • handlers:触发条件
  • files:文件
  • template:模板
  • default:默认,优先级最低

案例10:
把任务层独立出来

[root@ansible default]# cat include1.yml 
---
- hosts: cache
 remote_user: root
 tasks:
 - include: in3.yml    
   when: 2 > 1

[root@ansible default]# cat in3.yml 
- debug:
   msg: "task1 in in3.yml"
- debug:
   msg: "task2 in in3.yml"

[root@ansible default]# ansible-playbook include1.yml

4.9 debug调试
如果对于Python语法不熟悉的,playbook书写起来容易出错,且排错困难,这里介绍几种简单的排错调试方式

检测语法

  • ansible-playbook --syntax-check playbook.ymal
    显示受到影响的主机
  • --list-hosts
    显示工作的task
  • --list-tasks
    显示将要运行的tag
  • --list-tags

测试运行
模拟运行结果,但如果在任务列表中,任务2 需要任务1执行的结果,那么任务2可能会报错,因为任务1没有实际执行

  • ansible-playbook -C playbook.yaml

还可以在运行时输出更为详细的信息,帮助排错 比如:变量的值

案例11:
以之前when.yml为例,查看result变量中的内容

[root@ansible default]# cat  when.yml 
---
- hosts: web
  remote_user: root
  tasks:
  - shell: uptime|awk '{printf("%.2f\n",$(NF-2))}'
    register: result
  - name: stop  service
    service:
      name: httpd
      state: stopped
    when: result.stdout|float > 0.7
  - name: Show debug info
    debug:
      var: result

[root@ansible default]# ansible-playbook when.yml 

PLAY [web] ******************************************************************************************

TASK [Gathering Facts] ******************************************************************************
ok: [web1]
ok: [web2]

TASK [shell] ****************************************************************************************
changed: [web1]
changed: [web2]

TASK [stop  service] ********************************************************************************
skipping: [web1]
ok: [web2]

TASK [Show debug info] ******************************************************************************
ok: [web1] => {
    "result": {
        "changed": true, 
        "cmd": "uptime|awk '{printf(\"%.2f\\n\",$(NF-2))}'", 
        "delta": "0:00:00.010118", 
        "end": "2020-11-20 15:12:05.959884", 
        "failed": false, 
        "rc": 0, 
        "start": "2020-11-20 15:12:05.949766", 
        "stderr": "", 
        "stderr_lines": [], 
        "stdout": "0.04", 
        "stdout_lines": [
            "0.04"
        ]
    }
}
ok: [web2] => {
    "result": {
        "changed": true, 
        "cmd": "uptime|awk '{printf(\"%.2f\\n\",$(NF-2))}'", 
        "delta": "0:00:00.010133", 
        "end": "2020-11-20 15:12:05.484865", 
        "failed": false, 
        "rc": 0, 
        "start": "2020-11-20 15:12:05.474732", 
        "stderr": "", 
        "stderr_lines": [], 
        "stdout": "2.04", 
        "stdout_lines": [
            "2.04"
        ]
    }
}

PLAY RECAP ******************************************************************************************
web1                       : ok=3    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
web2                       : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容